diff options
author | Dmitry Petrashko <dark@d-d.me> | 2014-04-15 13:42:45 +0200 |
---|---|---|
committer | Dmitry Petrashko <dark@d-d.me> | 2014-04-15 13:42:45 +0200 |
commit | fae2c3f8e646fabedb633aea2f42405f556af602 (patch) | |
tree | c60b03c6f63d3be0424b883a96d9a8a49e8bbc77 /src/dotty | |
parent | 732a690ad2ef78450f6b8852b0f1f0ba892b392d (diff) | |
parent | d3adfd7f40708899aa033ea1e5c56d468ff9495c (diff) | |
download | dotty-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.scala | 11 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/Trees.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/ast/tpd.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/DenotTransformers.scala | 16 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Denotations.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Types.scala | 16 | ||||
-rw-r--r-- | src/dotty/tools/dotc/printing/RefinedPrinter.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Erasure.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/InterceptedMethods.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/LazyVals.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Nullarify.scala | 148 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/PatternMatcher.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/UncurryTreeTransform.scala | 13 |
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 |