aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/ElimByName.scala
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2016-11-02 11:08:28 +0100
committerGuillaume Martres <smarter@ubuntu.com>2016-11-22 01:35:07 +0100
commit8a61ff432543a29234193cd1f7c14abd3f3d31a0 (patch)
treea8147561d307af862c295cfc8100d271063bb0dd /compiler/src/dotty/tools/dotc/transform/ElimByName.scala
parent6a455fe6da5ff9c741d91279a2dc6fe2fb1b472f (diff)
downloaddotty-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.scala129
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
+}