diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-11-02 11:08:28 +0100 |
---|---|---|
committer | Guillaume Martres <smarter@ubuntu.com> | 2016-11-22 01:35:07 +0100 |
commit | 8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch) | |
tree | a8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/transform/ElimByName.scala | |
parent | 6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff) | |
download | dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.gz dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.tar.bz2 dotty-8a61ff432543a29234193cd1f7c14abd3f3d31a0.zip |
Move compiler and compiler tests to compiler dir
Diffstat (limited to 'compiler/src/dotty/tools/dotc/transform/ElimByName.scala')
-rw-r--r-- | compiler/src/dotty/tools/dotc/transform/ElimByName.scala | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/compiler/src/dotty/tools/dotc/transform/ElimByName.scala b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala new file mode 100644 index 000000000..192227261 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/ElimByName.scala @@ -0,0 +1,129 @@ +package dotty.tools.dotc +package transform + +import TreeTransforms._ +import core._ +import DenotTransformers._ +import Symbols._ +import SymDenotations._ +import Contexts._ +import Types._ +import Flags._ +import Decorators._ +import SymUtils._ +import util.Attachment +import core.StdNames.nme +import ast.Trees._ + +/** This phase eliminates ExprTypes `=> T` as types of function parameters, and replaces them by + * nullary function types. More precisely: + * + * For the types of parameter symbols: + * + * => T ==> () => T + * + * Note that `=> T` types are not eliminated in MethodTypes. This is done later at erasure. + * Terms are rewritten as follows: + * + * x ==> x.apply() if x is a parameter that had type => T + * + * Arguments to call-by-name parameters are translated as follows. First, the argument is + * rewritten by the rules + * + * e.apply() ==> e if e.apply() is an argument to a call-by-name parameter + * expr ==> () => expr if other expr is an argument to a call-by-name parameter + * + * This makes the argument compatible with a parameter type of () => T, which will be the + * formal parameter type at erasure. But to be -Ycheckable until then, any argument + * ARG rewritten by the rules above is again wrapped in an application DummyApply(ARG) + * where + * + * DummyApply: [T](() => T): T + * + * is a synthetic method defined in Definitions. Erasure will later strip these DummyApply wrappers. + * + * Note: This scheme to have inconsistent types between method types (whose formal types are still + * ExprTypes and parameter valdefs (which are now FunctionTypes) is not pretty. There are two + * other options which have been abandoned or not yet pursued. + * + * Option 1: Transform => T to () => T also in method and function types. The problem with this is + * that is that it requires to look at every type, and this forces too much, causing + * Cyclic Reference errors. Abandoned for this reason. + * + * Option 2: Merge ElimByName with erasure, or have it run immediately before. This has not been + * tried yet. + */ +class ElimByName extends MiniPhaseTransform with InfoTransformer { thisTransformer => + import ast.tpd._ + + override def phaseName: String = "elimByName" + + override def runsAfterGroupsOf = Set(classOf[Splitter]) + // assumes idents and selects have symbols; interferes with splitter distribution + // that's why it's "after group". + + /** The info of the tree's symbol at phase Nullarify (i.e. before transformation) */ + private def originalDenotation(tree: Tree)(implicit ctx: Context) = + tree.symbol.denot(ctx.withPhase(thisTransformer)) + + override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = + ctx.traceIndented(s"transforming ${tree.show} at phase ${ctx.phase}", show = true) { + + def transformArg(arg: Tree, formal: Type): Tree = formal.dealias match { + case formalExpr: ExprType => + val argType = arg.tpe.widen + val argFun = arg match { + case Apply(Select(qual, nme.apply), Nil) + if qual.tpe.derivesFrom(defn.FunctionClass(0)) && isPureExpr(qual) => + qual + case _ => + val inSuper = if (ctx.mode.is(Mode.InSuperCall)) InSuperCall else EmptyFlags + val meth = ctx.newSymbol( + ctx.owner, nme.ANON_FUN, Synthetic | Method | inSuper, MethodType(Nil, Nil, argType)) + Closure(meth, _ => arg.changeOwner(ctx.owner, meth)) + } + ref(defn.dummyApply).appliedToType(argType).appliedTo(argFun) + case _ => + arg + } + + val MethodType(_, formals) = tree.fun.tpe.widen + val args1 = tree.args.zipWithConserve(formals)(transformArg) + cpy.Apply(tree)(tree.fun, args1) + } + + /** If denotation had an ExprType before, it now gets a function type */ + private def exprBecomesFunction(symd: SymDenotation)(implicit ctx: Context) = + (symd is Param) || (symd is (ParamAccessor, butNot = Method)) + + /** Map `tree` to `tree.apply()` is `ftree` was of ExprType and becomes now a function */ + private def applyIfFunction(tree: Tree, ftree: Tree)(implicit ctx: Context) = { + val origDenot = originalDenotation(ftree) + if (exprBecomesFunction(origDenot) && (origDenot.info.isInstanceOf[ExprType])) + tree.select(defn.Function0_apply).appliedToNone + else tree + } + + override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree = + applyIfFunction(tree, tree) + + override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = tree match { + case TypeApply(Select(_, nme.asInstanceOf_), arg :: Nil) => + // tree might be of form e.asInstanceOf[x.type] where x becomes a function. + // See pos/t296.scala + applyIfFunction(tree, arg) + case _ => tree + } + + override def transformValDef(tree: ValDef)(implicit ctx: Context, info: TransformerInfo): Tree = + if (exprBecomesFunction(tree.symbol)) + cpy.ValDef(tree)(tpt = tree.tpt.withType(tree.symbol.info)) + else tree + + def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = tp match { + case ExprType(rt) if exprBecomesFunction(sym) => defn.FunctionOf(Nil, rt) + case _ => tp + } + + override def mayChange(sym: Symbol)(implicit ctx: Context): Boolean = sym.isTerm +} |