aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-04-14 14:42:05 +0200
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-04-15 11:07:36 +0200
commit0aa3f4cecfff4a2c883a5b814c551f399dc425e1 (patch)
treebd625a14416766af69547e9198a8610999013cef /src
parent2a681ecf7236fb2fdc128f7ab9d5e94d7889fc75 (diff)
downloaddotty-0aa3f4cecfff4a2c883a5b814c551f399dc425e1.tar.gz
dotty-0aa3f4cecfff4a2c883a5b814c551f399dc425e1.tar.bz2
dotty-0aa3f4cecfff4a2c883a5b814c551f399dc425e1.zip
New phase: Nullarify
Eliminates ExprTypes and PolyTypes over value types.
Diffstat (limited to 'src')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala11
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala5
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala2
-rw-r--r--src/dotty/tools/dotc/transform/LazyVals.scala1
-rw-r--r--src/dotty/tools/dotc/transform/Nullarify.scala148
5 files changed, 161 insertions, 6 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 2ba75c56b..457238da4 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -20,9 +20,14 @@ class Compiler {
def phases: List[List[Phase]] =
List(
List(new FrontEnd),
- List(new LazyValsCreateCompanionObjects, new TailRec), //force separataion between lazyVals and LVCreateCO
- List(new PatternMatcher, new LazyValTranformContext().transformer,
- new Splitter, new TypeTestsCasts, new InterceptedMethods),
+ List(new LazyValsCreateCompanionObjects,
+ new TailRec), //force separataion between lazyVals and LVCreateCO
+ List(new PatternMatcher,
+ new LazyValTranformContext().transformer,
+ new Splitter),
+ List(new Nullarify,
+ new TypeTestsCasts,
+ new InterceptedMethods),
List(new Erasure),
List(new UncurryTreeTransform)
)
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 53e8b4d2c..f1c69027e 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -341,6 +341,8 @@ class Definitions {
lazy val AbstractFunctionClass = mkArityArray("scala.runtime.AbstractFunction", MaxFunctionArity, 0)
lazy val FunctionClass = mkArityArray("scala.Function", MaxFunctionArity, 0)
+ lazy val Function0_apply = FunctionClass(0).requiredMethod(nme.apply)
+
lazy val TupleClass = mkArityArray("scala.Tuple", MaxTupleArity, 2)
lazy val ProductNClass = mkArityArray("scala.Product", MaxTupleArity, 2)
@@ -357,6 +359,7 @@ class Definitions {
lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf, Object_asInstanceOf)
lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf, Object_isInstanceOf)
+ lazy val typeTestsOrCasts = asInstanceOfMethods ++ isInstanceOfMethods
lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule)
@@ -440,7 +443,7 @@ class Definitions {
LongClass,
FloatClass,
DoubleClass)
-
+
lazy val ScalaValueClasses: collection.Set[Symbol] = ScalaNumericValueClasses + UnitClass + BooleanClass
lazy val ScalaBoxedClasses = ScalaValueClasses map boxedClass
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index d0c51c8b9..562a30682 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -28,7 +28,7 @@ class Erasure extends Phase with DenotTransformer {
override def name: String = "erasure"
/** List of names of phases that should precede this phase */
- override def runsAfter: Set[String] = Set("typeTestsCasts", "intercepted", "splitter")
+ override def runsAfter: Set[String] = Set("typeTestsCasts", "intercepted", "splitter", "nullarify")
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match {
case ref: SymDenotation =>
diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala
index cb5fb79cd..840ca0cdb 100644
--- a/src/dotty/tools/dotc/transform/LazyVals.scala
+++ b/src/dotty/tools/dotc/transform/LazyVals.scala
@@ -68,7 +68,6 @@ class LazyValTranformContext {
override def runsAfterGroupsOf: Set[String] = Set("lazyValsModules")
/** List of names of phases that should have finished their processing of all compilation units
* before this phase starts */
- override def runsAfter: Set[String] = Set("lazyValsModules")
/** List of names of phases that should have finished processing of tree
* before this phase starts processing same tree */
diff --git a/src/dotty/tools/dotc/transform/Nullarify.scala b/src/dotty/tools/dotc/transform/Nullarify.scala
new file mode 100644
index 000000000..8ca41c07f
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/Nullarify.scala
@@ -0,0 +1,148 @@
+package dotty.tools.dotc
+package transform
+
+import TreeTransforms._
+import core.DenotTransformers._
+import core.Symbols._
+import core.Contexts._
+import core.Types._
+import core.Flags._
+import core.Decorators._
+import core.StdNames.nme
+import ast.Trees._
+
+/** This phase eliminates ExprTypes `=> T` and PolyTypes over value types `[X]T`.
+ * They are expressed in terms of nullary method or function types. More precisely:
+ *
+ * For types:
+ *
+ * => T ==> () => T if T is the type of a parameter
+ * ==> ()T otherwise
+ * [X]T ==> [X]()T
+ *
+ * For definitions:
+ *
+ * def f: R ==> def f(): R
+ * def f[X]: R ==> def f[X](): R
+ * (x: => T) ==> (x: () => T)
+ *
+ * For terms:
+ *
+ * f ==> f() if f had type => T and is not a parameter
+ * x ==> x.apply() if x is a parameter that had type => T
+ * 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
+ *
+ */
+class Nullarify extends TreeTransform with InfoTransformer {
+ import ast.tpd._
+
+ override def name: String = "nullarify"
+
+ override def runsAfterGroupsOf: Set[String] = Set("splitter")
+ // assumes idents and selects have symbols; interferes with splitter distribution
+ // that's why it's "after group".
+
+ 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 match {
+ case _: ExprType =>
+ arg match {
+ case Apply(Select(qual, nme.apply), Nil) => qual
+ case _ =>
+ val meth = ctx.newSymbol(ctx.owner, nme.ANON_FUN, Synthetic,
+ MethodType(Nil, Nil, arg.tpe.widen))
+ Closure(meth, _ => arg)
+ }
+ case _ =>
+ arg
+ }
+
+ // Compute the method type tree had before this phase is run.
+ // This is needed to find out which parameters are by-name.
+ val funType = tree.fun.symbol.info match {
+ case info: PolyType => info.resultType
+ case info => info
+ }
+ def methType(info: Type, tree: Tree): Type = tree match {
+ case Apply(fn, args) => methType(info.resultType, fn)
+ case _ => info
+ }
+ val MethodType(_, formals) = methType(funType, tree.fun)
+
+ val args1 = tree.args.zipWithConserve(formals)(transformArg)
+ cpy.Apply(tree, tree.fun, args1) withType nullarify(tree.tpe)
+ }
+
+ /** Insert () or .apply() if the term refers to something that was converted to a
+ * nullary method. Also, transform its type.
+ */
+ def insertParens(tree: Tree)(implicit ctx: Context): Tree = {
+ val tp1 = transformInfo(tree.tpe, tree.symbol)
+ val tree1 = tree.withType(tp1)
+ val origType = tree.tpe.widenSingleton
+ def result(implicit ctx: Context) = {
+ tp1.widen match {
+ case MethodType(Nil, _) if origType.widenExpr.isInstanceOf[ValueType] =>
+ Apply(tree1, Nil)
+ case _ =>
+ origType match {
+ case _: ExprType => // it's a by-name parameter
+ Apply(Select(tree1, defn.Function0_apply), Nil)
+ case _ =>
+ tree1
+ }
+ }
+ }
+ result(ctx.withPhase(ctx.phase.next))
+ }
+
+ override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
+ insertParens(tree)
+
+ override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
+ insertParens(tree)
+
+ override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree =
+ insertParens(tree)
+
+ override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val DefDef(mods, name, tparams, vparamss, tpt, rhs) = tree
+ val vparamss1 =
+ if (vparamss.isEmpty) Nil :: Nil
+ else vparamss nestedMap { vparam =>
+ val tp = vparam.tpt.tpe
+ val tp1 = nullarifyParam(tp)
+ if (tp eq tp1) vparam
+ else cpy.ValDef(vparam, vparam.mods, vparam.name, vparam.tpt.withType(tp1), vparam.rhs)
+ }
+ cpy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs)
+ }
+
+ def nullarify(tp: Type)(implicit ctx: Context): Type = tp match {
+ case ExprType(rt) =>
+ MethodType(Nil, Nil, rt)
+ case pt: PolyType =>
+ val rt = pt.resultType match {
+ case mt: MethodType => nullarify(mt)
+ case rt => MethodType(Nil, Nil, rt)
+ }
+ pt.derivedPolyType(pt.paramNames, pt.paramBounds, rt)
+ case mt: MethodType =>
+ mt.derivedMethodType(mt.paramNames, mt.paramTypes mapConserve nullarifyParam,
+ nullarify(mt.resultType))
+ case _ =>
+ tp
+ }
+
+ def nullarifyParam(tp: Type)(implicit ctx: Context) = tp match {
+ case ExprType(rt) => defn.FunctionType(Nil, rt)
+ case _ => tp
+ }
+
+ def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
+ if (defn.typeTestsOrCasts contains sym) tp
+ else if (sym is Param) nullarifyParam(tp)
+ else nullarify(tp)
+} \ No newline at end of file