aboutsummaryrefslogtreecommitdiff
path: root/src/dotty
diff options
context:
space:
mode:
authorDmitry Petrashko <dark@d-d.me>2014-04-15 13:42:45 +0200
committerDmitry Petrashko <dark@d-d.me>2014-04-15 13:42:45 +0200
commitfae2c3f8e646fabedb633aea2f42405f556af602 (patch)
treec60b03c6f63d3be0424b883a96d9a8a49e8bbc77 /src/dotty
parent732a690ad2ef78450f6b8852b0f1f0ba892b392d (diff)
parentd3adfd7f40708899aa033ea1e5c56d468ff9495c (diff)
downloaddotty-fae2c3f8e646fabedb633aea2f42405f556af602.tar.gz
dotty-fae2c3f8e646fabedb633aea2f42405f556af602.tar.bz2
dotty-fae2c3f8e646fabedb633aea2f42405f556af602.zip
Merge pull request #122 from dotty-staging/transform/nullarify
Transform/nullarify
Diffstat (limited to 'src/dotty')
-rw-r--r--src/dotty/tools/dotc/Compiler.scala11
-rw-r--r--src/dotty/tools/dotc/ast/Trees.scala2
-rw-r--r--src/dotty/tools/dotc/ast/tpd.scala2
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala5
-rw-r--r--src/dotty/tools/dotc/core/DenotTransformers.scala16
-rw-r--r--src/dotty/tools/dotc/core/Denotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/Types.scala16
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala5
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala2
-rw-r--r--src/dotty/tools/dotc/transform/InterceptedMethods.scala2
-rw-r--r--src/dotty/tools/dotc/transform/LazyVals.scala1
-rw-r--r--src/dotty/tools/dotc/transform/Nullarify.scala148
-rw-r--r--src/dotty/tools/dotc/transform/PatternMatcher.scala1
-rw-r--r--src/dotty/tools/dotc/transform/TypeTestsCasts.scala1
-rw-r--r--src/dotty/tools/dotc/transform/UncurryTreeTransform.scala13
15 files changed, 198 insertions, 29 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/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala
index f69ee265e..2ae494d55 100644
--- a/src/dotty/tools/dotc/ast/Trees.scala
+++ b/src/dotty/tools/dotc/ast/Trees.scala
@@ -639,7 +639,7 @@ object Trees {
/** => T */
case class ByNameTypeTree[-T >: Untyped] private[ast] (result: Tree[T])
- extends Tree[T] {
+ extends TypTree[T] {
type ThisTree[-T >: Untyped] = ByNameTypeTree[T]
}
diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala
index 8b175721f..e9775f1dc 100644
--- a/src/dotty/tools/dotc/ast/tpd.scala
+++ b/src/dotty/tools/dotc/ast/tpd.scala
@@ -30,7 +30,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
def Select(qualifier: Tree, sym: Symbol)(implicit ctx: Context): Select =
untpd.Select(qualifier, sym.name).withType(
- TermRef.withSig(qualifier.tpe, sym.name.asTermName, sym.signature, sym.denot))
+ TermRef.withSig(qualifier.tpe, sym.name.asTermName, sym.signature, sym.denot.asSeenFrom(qualifier.tpe)))
def SelectWithSig(qualifier: Tree, name: Name, sig: Signature)(implicit ctx: Context) =
untpd.SelectWithSig(qualifier, name, sig)
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/core/DenotTransformers.scala b/src/dotty/tools/dotc/core/DenotTransformers.scala
index e1ee355d8..6daa028fc 100644
--- a/src/dotty/tools/dotc/core/DenotTransformers.scala
+++ b/src/dotty/tools/dotc/core/DenotTransformers.scala
@@ -5,6 +5,7 @@ import Periods._
import SymDenotations._
import Contexts._
import Types._
+import Symbols._
import Denotations._
import Phases._
import java.lang.AssertionError
@@ -30,4 +31,19 @@ object DenotTransformers {
/** The transformation method */
def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation
}
+
+ trait InfoTransformer extends DenotTransformer {
+
+ def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type
+
+ /** The transformation method */
+ def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
+ val info1 = transformInfo(ref.info, ref.symbol)
+ if (info1 eq ref.info) ref
+ else ref match {
+ case ref: SymDenotation => ref.copySymDenotation(info = info1)
+ case _ => ref.derivedSingleDenotation(ref.symbol, info1)
+ }
+ }
+ }
}
diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala
index 63b94efbd..e5f5e6f87 100644
--- a/src/dotty/tools/dotc/core/Denotations.scala
+++ b/src/dotty/tools/dotc/core/Denotations.scala
@@ -512,7 +512,7 @@ object Denotations {
def current(implicit ctx: Context): SingleDenotation = {
val currentPeriod = ctx.period
val valid = myValidFor
- assert(valid.code > 0, s"negative period $valid: ${valid.code}")
+ assert(valid.code > 0)
if (valid.runId != currentPeriod.runId) bringForward.current
else {
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index c348e246c..66f027915 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -352,6 +352,12 @@ object Types {
goThis(tp)
case tp: TypeRef =>
tp.denot.findMember(name, pre, excluded)
+ case tp: TermRef =>
+ go (tp.underlying match {
+ case mt: MethodType
+ if mt.paramTypes.isEmpty && (tp.symbol is Stable) => mt.resultType
+ case tp1 => tp1
+ })
case tp: TypeProxy =>
go(tp.underlying)
case tp: ClassInfo =>
@@ -449,7 +455,7 @@ object Types {
final def implicitMembers(implicit ctx: Context): List[TermRef] = track("implicitMembers") {
memberDenots(implicitFilter,
(name, buf) => buf ++= member(name).altsWith(_ is Implicit))
- .toList.map(_.termRefWithSig)
+ .toList.map(d => TermRef.withSig(this, d.symbol.asTerm))
}
/** The info of `sym`, seen as a member of this type. */
@@ -1101,14 +1107,14 @@ object Types {
private def withSig(sig: Signature)(implicit ctx: Context): NamedType =
TermRef.withSig(prefix, name.asTermName, sig)
- protected def loadDenot(implicit ctx: Context) = {
+ protected def loadDenot(implicit ctx: Context): Denotation = {
val d =
if (name.isInheritedName) prefix.nonPrivateMember(name.revertInherited)
else prefix.member(name)
- if (d.exists || ctx.phaseId == FirstPhaseId)
+ if (d.exists || ctx.phaseId == FirstPhaseId || !lastDenotation.isInstanceOf[SymDenotation])
d
else {// name has changed; try load in earlier phase and make current
- val d = denot(ctx.withPhase(ctx.phaseId - 1)).current
+ val d = loadDenot(ctx.withPhase(ctx.phaseId - 1)).current
if (d.exists) d
else throw new Error(s"failure to reload $this")
}
@@ -1311,7 +1317,7 @@ object Types {
if (prefix eq NoPrefix) withNonMemberSym(prefix, name, sym)
else {
if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature)
- else apply(prefix, name)
+ else apply(prefix, name)
} withSym (sym, Signature.NotAMethod)
def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef =
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index f9cd9ec72..dd8f04d92 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -54,13 +54,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
}
override def toTextPrefix(tp: Type): Text = controlled {
+ def isOmittable(sym: Symbol) = isOmittablePrefix(sym) && !ctx.settings.verbose.value
tp match {
case ThisType(cls) =>
- if (isOmittablePrefix(cls)) return ""
+ if (isOmittable(cls)) return ""
case tp @ TermRef(pre, _) =>
val sym = tp.symbol
if (sym.isPackageObject) return toTextPrefix(pre)
- if (isOmittablePrefix(sym)) return ""
+ if (isOmittable(sym)) return ""
case _ =>
}
super.toTextPrefix(tp)
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/InterceptedMethods.scala b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
index b56985ffe..d5a4377d0 100644
--- a/src/dotty/tools/dotc/transform/InterceptedMethods.scala
+++ b/src/dotty/tools/dotc/transform/InterceptedMethods.scala
@@ -2,7 +2,6 @@ package dotty.tools.dotc
package transform
import TreeTransforms._
-import core.DenotTransformers._
import core.Denotations._
import core.SymDenotations._
import core.Contexts._
@@ -27,7 +26,6 @@ import dotty.runtime.LazyVals
import scala.collection.mutable.ListBuffer
import dotty.tools.dotc.core.Denotations.SingleDenotation
import dotty.tools.dotc.core.SymDenotations.SymDenotation
-import dotty.tools.dotc.core.DenotTransformers.DenotTransformer
import StdNames._
/** Replace member references as follows:
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..664b4bee1
--- /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) if qual.tpe <:< defn.FunctionClass(0).typeRef => 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
diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala
index ff25a94de..40a157483 100644
--- a/src/dotty/tools/dotc/transform/PatternMatcher.scala
+++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala
@@ -2,7 +2,6 @@ package dotty.tools.dotc
package transform
import TreeTransforms._
-import core.DenotTransformers._
import core.Denotations._
import core.SymDenotations._
import core.Contexts._
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
index aba674d1c..a36bf6500 100644
--- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
+++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
@@ -2,7 +2,6 @@ package dotty.tools.dotc
package transform
import TreeTransforms._
-import core.DenotTransformers._
import core.Denotations._
import core.SymDenotations._
import core.Contexts._
diff --git a/src/dotty/tools/dotc/transform/UncurryTreeTransform.scala b/src/dotty/tools/dotc/transform/UncurryTreeTransform.scala
index fe50e41cd..ccfaaa0dc 100644
--- a/src/dotty/tools/dotc/transform/UncurryTreeTransform.scala
+++ b/src/dotty/tools/dotc/transform/UncurryTreeTransform.scala
@@ -7,10 +7,11 @@ import core.Denotations._
import core.SymDenotations._
import core.Contexts._
import core.Types._
+import core.Symbols._
import ast.Trees._
import ast.tpd.{Apply, Tree, cpy}
-class UncurryTreeTransform extends TreeTransform with DenotTransformer {
+class UncurryTreeTransform extends TreeTransform with InfoTransformer {
override def name: String = "uncurry"
override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree =
@@ -40,12 +41,6 @@ class UncurryTreeTransform extends TreeTransform with DenotTransformer {
tp
}
- def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = {
- val info1 = uncurry(ref.info)
- if (info1 eq ref.info) ref
- else ref match {
- case ref: SymDenotation => ref.copySymDenotation(info = info1)
- case _ => ref.derivedSingleDenotation(ref.symbol, info1)
- }
- }
+ def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
+ uncurry(tp)
} \ No newline at end of file