From dd53b26706254985ba6b4faa9c89272571857906 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 27 Mar 2014 15:02:02 +0100 Subject: [PATCH 01/13] Fixing completion phase A completer for a lazytype should run in the first phase of the validity period of the denotation that gets completed. --- src/dotty/tools/dotc/config/Settings.scala | 1 - src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/config/Settings.scala b/src/dotty/tools/dotc/config/Settings.scala index b3bf2f1348be..17d4d67125e8 100644 --- a/src/dotty/tools/dotc/config/Settings.scala +++ b/src/dotty/tools/dotc/config/Settings.scala @@ -223,7 +223,6 @@ object Settings { setting } - def BooleanSetting(name: String, descr: String): Setting[Boolean] = publish(Setting(name, descr, false)) diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index f07eaa2bebdc..e96f08855a9c 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -147,7 +147,7 @@ object SymDenotations { myFlags |= Touched // completions.println(s"completing ${this.debugString}") - try completer.complete(this) + try completer.complete(this)(ctx.withPhase(validFor.firstPhaseId)) catch { case ex: CyclicReference => completions.println(s"error while completing ${this.debugString}") From c62d021cdcc0a3dda6daffd74daf8eaf48aeae88 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Mar 2014 12:57:54 +0100 Subject: [PATCH 02/13] Fix in NamedType#denot Need to update checkedPeriod when new denotation is computed. --- src/dotty/tools/dotc/core/Types.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index a7a33ce8e20e..8799f9fd0474 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -1039,6 +1039,7 @@ object Types { } lastDenotation = d lastSymbol = d.symbol + checkedPeriod = ctx.period d } From ad437d8fa9bd4127889569952ae6fdb048d2b1ec Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Mar 2014 13:00:28 +0100 Subject: [PATCH 03/13] Make primitive conversions work also for non-numeric types If the arguments to a primitive conversion are not both numbers, the conversion will either return the argument itself, or throw a ClassCastException. --- src/dotty/tools/dotc/ast/tpd.scala | 13 ++++++++++--- src/dotty/tools/dotc/core/Definitions.scala | 1 + src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 173f8189401b..3f29fc72f6f7 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -7,6 +7,7 @@ import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._ import CheckTrees._, Denotations._, Decorators._ import config.Printers._ +import typer.ErrorReporting._ /** Some creators for typed trees */ object tpd extends Trees.Instance[Type] with TypedTreeInfo { @@ -400,11 +401,17 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { } // convert a numeric with a toXXX method - def numericConversion(tree: Tree, numericCls: Symbol)(implicit ctx: Context): Tree = { + def primitiveConversion(tree: Tree, numericCls: Symbol)(implicit ctx: Context): Tree = { val mname = ("to" + numericCls.name).toTermName val conversion = tree.tpe member mname - assert(conversion.symbol.exists, s"$tree => $numericCls") - ensureApplied(Select(tree, conversion.symbol.termRef)) + if (conversion.symbol.exists) + ensureApplied(Select(tree, conversion.symbol.termRef)) + else if (tree.tpe.widen isRef numericCls) + tree + else { + ctx.warning(i"conversion from ${tree.tpe.widen} to ${numericCls.typeRef} will always fail at runtime.") + Throw(New(defn.ClassCastExceptionClass.typeRef, Nil)) withPos tree.pos + } } def evalOnce(tree: Tree)(within: Tree => Tree)(implicit ctx: Context) = { diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 3ae74b467419..311abd8e1dd9 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -218,6 +218,7 @@ class Definitions { lazy val OptionClass = ctx.requiredClass("scala.Option") lazy val BoxedNumberClass = ctx.requiredClass("java.lang.Number") lazy val ThrowableClass = ctx.requiredClass("java.lang.Throwable") + lazy val ClassCastExceptionClass = ctx.requiredClass("java.lang.ClassCastException") lazy val JavaSerializableClass = ctx.requiredClass("java.lang.Serializable") lazy val ComparableClass = ctx.requiredClass("java.lang.Comparable") lazy val ProductClass = ctx.requiredClass("scala.Product") diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index 1c453750ea56..48a377c020be 100644 --- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -81,7 +81,7 @@ class TypeTestsCasts extends TreeTransform { Typed(qual, tree.args.head) else if (qualCls.isPrimitiveValueClass) { val argCls = argType.classSymbol - if (argCls.isPrimitiveValueClass) numericConversion(qual, argCls) + if (argCls.isPrimitiveValueClass) primitiveConversion(qual, argCls) else derivedTree(box(qual), defn.Object_asInstanceOf) } else From e5d51859bd3d6fd0b286aa6c8e710f33f95b97cd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Mar 2014 13:11:17 +0100 Subject: [PATCH 04/13] Added dummy pattern matcher at the place forseen for the real pattern matcher, so that following transformations do not have to deal with patterns. --- src/dotty/tools/dotc/Compiler.scala | 2 +- .../tools/dotc/transform/PatternMatcher.scala | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/dotty/tools/dotc/transform/PatternMatcher.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 709f4b2db299..6fd69beb8151 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -20,7 +20,7 @@ class Compiler { def phases: List[List[Phase]] = List( List(new FrontEnd), - List(new LazyValsCreateCompanionObjects), //force separataion between lazyVals and LVCreateCO + List(new LazyValsCreateCompanionObjects, new PatternMatcher), //force separataion between lazyVals and LVCreateCO List(new LazyValTranformContext().transformer, new TypeTestsCasts), List(new Erasure), List(new UncurryTreeTransform) diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala new file mode 100644 index 000000000000..ff25a94de85f --- /dev/null +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -0,0 +1,27 @@ +package dotty.tools.dotc +package transform + +import TreeTransforms._ +import core.DenotTransformers._ +import core.Denotations._ +import core.SymDenotations._ +import core.Contexts._ +import core.Symbols._ +import core.Types._ +import core.Constants._ +import core.StdNames._ +import core.transform.Erasure.isUnboundedGeneric +import typer.ErrorReporting._ +import ast.Trees._ + +/** This transform eliminates patterns. Right now it's a dummy. + * Awaiting the real pattern matcher. + */ +class PatternMatcher extends TreeTransform { + import ast.tpd._ + + override def name: String = "patternMatcher" + + override def transformCaseDef(tree: CaseDef)(implicit ctx: Context, info: TransformerInfo): Tree = + cpy.CaseDef(tree, Literal(Constant("")), tree.guard, tree.body) +} \ No newline at end of file From a73b510b82460247524a07a6dd4f0bfaac74ccfc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Mar 2014 13:07:22 +0100 Subject: [PATCH 05/13] Avoiding type applications after erasure. Methods appliedTo and translateParameterizes only apply before erasure (except on arrays). Also, computation of a potential expensive yet redundant lub in assignType(SeqLiteral) is avoided. --- src/dotty/tools/dotc/core/TypeApplications.scala | 11 ++++++++--- src/dotty/tools/dotc/typer/TypeAssigner.scala | 8 ++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 9cd635cd9f38..4b251f1839e2 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -39,6 +39,8 @@ import TypeApplications._ /** A decorator that provides methods for modeling type application */ class TypeApplications(val self: Type) extends AnyVal { + def canHaveTypeParams(implicit ctx: Context) = !ctx.erasedTypes || self.isRef(defn.ArrayClass) + /** The type parameters of this type are: * For a ClassInfo type, the type parameters of its class. * For a typeref referring to a class, the type parameters of the class. @@ -128,7 +130,7 @@ class TypeApplications(val self: Type) extends AnyVal { defn.hkTrait(args map alwaysZero).typeParams } - if (args.isEmpty) self + if (args.isEmpty || !canHaveTypeParams) self else self match { case tp: TypeRef => val tsym = tp.symbol @@ -228,8 +230,11 @@ class TypeApplications(val self: Type) extends AnyVal { * `from` and `to` must be static classes, both with one type parameter, and the same variance. */ def translateParameterized(from: ClassSymbol, to: ClassSymbol)(implicit ctx: Context): Type = - if (self derivesFrom from) - RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info) + if (self.derivesFrom(from)) + if (canHaveTypeParams) + RefinedType(to.typeRef, to.typeParams.head.name, self.member(from.typeParams.head.name).info) + else + to.typeRef else self /** If this is an encoding of a (partially) applied type, return its arguments, diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 8be73ac82d01..3060f3951dee 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -274,8 +274,12 @@ trait TypeAssigner { def assignType(tree: untpd.Throw)(implicit ctx: Context) = tree.withType(defn.NothingType) - def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = - tree.withType(defn.SeqType.appliedTo(ctx.typeComparer.lub(elems.tpes))) + def assignType(tree: untpd.SeqLiteral, elems: List[Tree])(implicit ctx: Context) = { + val ownType = + if (ctx.erasedTypes) defn.SeqType + else defn.SeqType.appliedTo(ctx.typeComparer.lub(elems.tpes)) + tree.withType(ownType) + } def assignType(tree: untpd.SingletonTypeTree, ref: Tree)(implicit ctx: Context) = tree.withType(ref.tpe) From 26b8ec48adec709cf2b07b470ada774c708e96a4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 29 Mar 2014 15:02:51 +0100 Subject: [PATCH 06/13] Adapting containsPhase to phase groups A list of names contains a phasegroup if it contains any phase in the group. --- src/dotty/tools/dotc/core/Decorators.scala | 7 +++++-- src/dotty/tools/dotc/core/Phases.scala | 4 ++-- src/dotty/tools/dotc/transform/TreeTransform.scala | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/dotty/tools/dotc/core/Decorators.scala b/src/dotty/tools/dotc/core/Decorators.scala index cd9680e64d94..21f914d9903f 100644 --- a/src/dotty/tools/dotc/core/Decorators.scala +++ b/src/dotty/tools/dotc/core/Decorators.scala @@ -6,6 +6,7 @@ import Symbols._ import Contexts._, Names._, Phases._, printing.Texts._, printing.Printer import util.Positions.Position, util.SourcePosition import collection.mutable.ListBuffer +import dotty.tools.dotc.transform.TreeTransforms._ import scala.language.implicitConversions /** This object provides useful implicit decorators for types defined elsewhere */ @@ -127,8 +128,10 @@ object Decorators { * one of the names in the list of strings. */ implicit class PhaseListDecorator(val names: List[String]) extends AnyVal { - def containsPhase(phase: Phase) = - names exists (phase.name.startsWith) + def containsPhase(phase: Phase): Boolean = phase match { + case phase: TreeTransformer => phase.transformations.exists(containsPhase) + case _ => names exists (phase.name.startsWith) + } } implicit def sourcePos(pos: Position)(implicit ctx: Context): SourcePosition = diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index 87242c9b5b37..8b5606da245b 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -107,11 +107,11 @@ object Phases { postTyperEmmited = true new PostTyperTransformer { override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}") - override protected def transformations: Array[TreeTransform] = transforms.toArray + override def transformations: Array[TreeTransform] = transforms.toArray } } else new TreeTransformer { override def name: String = transformations.map(_.name).mkString("TreeTransform:{", ", ", "}") - override protected def transformations: Array[TreeTransform] = transforms.toArray + override def transformations: Array[TreeTransform] = transforms.toArray } squashedPhases += block block.init(this, phasess(i).head.id, phasess(i).last.id) diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index 10857da5afc9..6847141991c8 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -129,7 +129,7 @@ object TreeTransforms { protected def mkTreeTransformer = new TreeTransformer { override def name: String = TreeTransform.this.name - override protected def transformations = Array(TreeTransform.this) + override def transformations = Array(TreeTransform.this) } override def run(implicit ctx: Context): Unit = { @@ -414,7 +414,7 @@ object TreeTransforms { /** A group of tree transforms that are applied in sequence during the same phase */ abstract class TreeTransformer extends Phase { - protected def transformations: Array[TreeTransform] + def transformations: Array[TreeTransform] override def run(implicit ctx: Context): Unit = { val curTree = ctx.compilationUnit.tpdTree From fc4648d33a051ff5d220c2fea097fc99b5883ecc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 29 Mar 2014 15:05:07 +0100 Subject: [PATCH 07/13] Add -Ycheck capability Right now uses a super-rudementary tree checker: we only check that every tree has a type. --- src/dotty/tools/dotc/Run.scala | 12 +++--- .../tools/dotc/config/ScalaSettings.scala | 2 +- .../tools/dotc/transform/TreeChecker.scala | 37 +++++++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 src/dotty/tools/dotc/transform/TreeChecker.scala diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index 3f15bd4c3597..264373baff93 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -6,6 +6,7 @@ import Contexts._, Periods._, Symbols._, Phases._, Decorators._ import io.PlainFile import util.{SourceFile, NoSource, Stats, SimpleMap} import reporting.Reporter +import transform.TreeChecker import java.io.{BufferedWriter, OutputStreamWriter} import scala.reflect.io.VirtualFile @@ -39,18 +40,19 @@ class Run(comp: Compiler)(implicit ctx: Context) { for (phase <- phasesToRun) { if (!ctx.reporter.hasErrors) { phase.runOn(units) - if (ctx.settings.Xprint.value.containsPhase(phase)) - for (unit <- units) - printTree(ctx.fresh.setPhase(phase).setCompilationUnit(unit)) + def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit = + for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) + if (ctx.settings.Xprint.value.containsPhase(phase)) foreachUnit(printTree) + if (ctx.settings.Ycheck.value.containsPhase(phase)) foreachUnit(TreeChecker.check) } } } } - private def printTree(implicit ctx: Context) = { + private def printTree(ctx: Context) = { val unit = ctx.compilationUnit println(s"result of $unit after ${ctx.phase}:") - println(unit.tpdTree.show) + println(unit.tpdTree.show(ctx)) } def compile(sourceCode: String): Unit = { diff --git a/src/dotty/tools/dotc/config/ScalaSettings.scala b/src/dotty/tools/dotc/config/ScalaSettings.scala index 8ed725e36789..144e146c155c 100644 --- a/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -97,7 +97,7 @@ class ScalaSettings extends Settings.SettingGroup { val overrideVars = BooleanSetting("-Yoverride-vars", "Allow vars to be overridden.") val Yhelp = BooleanSetting("-Y", "Print a synopsis of private options.") val browse = PhasesSetting("-Ybrowse", "Browse the abstract syntax tree after") - val check = PhasesSetting("-Ycheck", "Check the tree at the end of") + val Ycheck = PhasesSetting("-Ycheck", "Check the tree at the end of") val YcheckTypedTrees = BooleanSetting("-YcheckTypedTrees", "Check all constructured typed trees for type correctness") val Yshow = PhasesSetting("-Yshow", "(Requires -Xshow-class or -Xshow-object) Show after") val Xcloselim = BooleanSetting("-Yclosure-elim", "Perform closure elimination.") diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala new file mode 100644 index 000000000000..ea3afc67905f --- /dev/null +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -0,0 +1,37 @@ +package dotty.tools.dotc +package transform + +import TreeTransforms._ +import core.DenotTransformers._ +import core.Denotations._ +import core.SymDenotations._ +import core.Contexts._ +import core.Symbols._ +import core.Types._ +import core.Constants._ +import core.StdNames._ +import core.transform.Erasure.isUnboundedGeneric +import typer.ErrorReporting._ +import ast.Trees._ + +/** This transform eliminates patterns. Right now it's a dummy. + * Awaiting the real pattern matcher. + */ +class TreeChecker { + import ast.tpd._ + + def check(ctx: Context) = { + println(s"checking ${ctx.compilationUnit} after phase ${ctx.phase.prev}") + Checker.transform(ctx.compilationUnit.tpdTree)(ctx) + } + + object Checker extends TreeMap { + override def transform(tree: Tree)(implicit ctx: Context) = { + println(i"checking $tree") + assert(tree.isEmpty || tree.hasType, tree.show) + super.transform(tree) + } + } +} + +object TreeChecker extends TreeChecker \ No newline at end of file From 9bd1e6a99e1cb09a3527e548699d1561e72e36d3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 10:49:42 +0200 Subject: [PATCH 08/13] More fixes and tests for easure. 1. Object_isInstanceOf/asInstanceOf are no longer parameterized methods (seems there's no point in writing x.$asInstanceOf[T]() instead of the shorter x.$asInstanceOf[T]). 2. Array constructor's type is unchanged (the previous rules erased it to def (len: Int)Object which is clearly wrong). 3. indexing needs to be disabled. 4. typedTypeApply needs to keep type applications that apply to type tests and type casts as well as array ops. 5. References to self-ids are typed ThisType(cls) before erasure; are replaced by This(cls) references during erasure. --- src/dotty/tools/dotc/core/Definitions.scala | 4 +- .../tools/dotc/core/transform/Erasure.scala | 17 +++--- src/dotty/tools/dotc/transform/Erasure.scala | 25 ++++++--- src/dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- test/dotc/tests.scala | 54 ++++++++++--------- tests/pos/unions.scala | 14 +++++ 6 files changed, 69 insertions(+), 47 deletions(-) create mode 100644 tests/pos/unions.scala diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 311abd8e1dd9..46878d3cabe1 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -103,8 +103,8 @@ class Definitions { lazy val Object_!= = newMethod(ObjectClass, nme.NE, methOfAny(BooleanType), Final) lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final) lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final) - lazy val Object_isInstanceOf = newT1EmptyParamsMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic) - lazy val Object_asInstanceOf = newT1EmptyParamsMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic) + lazy val Object_isInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic) + lazy val Object_asInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic) lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1, pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final) diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala index d59bdf1a917b..842e2f81f7f4 100644 --- a/src/dotty/tools/dotc/core/transform/Erasure.scala +++ b/src/dotty/tools/dotc/core/transform/Erasure.scala @@ -61,16 +61,11 @@ object Erasure { */ def transformInfo(sym: Symbol, tp: Type)(implicit ctx: Context): Type = { val erase = erasureFn(sym is JavaDefined, isSemi = true, sym.isConstructor, wildcardOK = false) - if ((sym eq defn.Object_asInstanceOf) || sym.isType && (sym.owner eq defn.ArrayClass)) - sym.info - else if ((sym eq defn.Object_isInstanceOf) || (sym eq defn.ArrayClass.primaryConstructor)) { - val tp @ PolyType(pnames) = sym.info - tp.derivedPolyType(pnames, TypeBounds.empty :: Nil, erase(tp.resultType)) - } - else if (sym.isAbstractType) - TypeAlias(WildcardType) - else - erase(tp) + if ((sym eq defn.Object_asInstanceOf) || + (sym eq defn.Object_isInstanceOf) || + (sym.owner eq defn.ArrayClass) && (sym.isType || sym.isConstructor)) sym.info + else if (sym.isAbstractType) TypeAlias(WildcardType) + else erase(tp) } def isUnboundedGeneric(tp: Type)(implicit ctx: Context) = !( @@ -120,7 +115,7 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard case tp: TypeRef => val sym = tp.symbol if (!sym.isClass) - if (sym.owner eq defn.ArrayClass) tp else this(tp.info) + if (sym.exists && (sym.owner eq defn.ArrayClass)) tp else this(tp.info) //!!!! else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tp) else eraseNormalClassRef(tp) case tp: RefinedType => diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index f9b602f54cc9..b403d4e66fa8 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -130,7 +130,7 @@ object Erasure { // See SI-2386 for one example of when this might be necessary. cast(runtimeCall(nme.toObjectArray, tree :: Nil), pt) case _ => - println(s"casting from ${tree.showSummary}: ${tree.tpe.show} to ${pt.show}") + ctx.log(s"casting from ${tree.showSummary}: ${tree.tpe.show} to ${pt.show}") TypeApply(Select(tree, defn.Object_asInstanceOf), TypeTree(pt) :: Nil) } @@ -173,8 +173,10 @@ object Erasure { override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = { val tree1 = promote(tree) - println(i"typed ident ${tree.name}: ${tree1.tpe} at phase ${ctx.phase}, history = ${tree1.symbol.history}") - tree1 + tree1.tpe match { + case ThisType(cls) => This(cls) withPos tree.pos + case _ => tree1 + } } /** Type check select nodes, applying the following rewritings exhaustively @@ -226,8 +228,16 @@ object Erasure { recur(typed(tree.qualifier, AnySelectionProto)) } - override def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context) = - typedExpr(tree.fun, pt) + override def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context) = { + val TypeApply(fun, args) = tree + val fun1 = typedExpr(fun, pt) + fun1.tpe.widen match { + case funTpe: PolyType => + val args1 = args.mapconserve(typedType(_)) + untpd.cpy.TypeApply(tree, fun1, args1).withType(funTpe.instantiate(args1.tpes)) + case _ => fun1 + } + } override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { val Apply(fun, args) = tree @@ -268,9 +278,8 @@ object Erasure { */ override def typedNamed(tree: untpd.NameTree, pt: Type)(implicit ctx: Context): Tree = { if (tree eq untpd.EmptyValDef) return tpd.EmptyValDef - assert(tree.hasType, tree) + assert(tree.hasType, tree.show) val sym = tree.symbol - assert(sym.exists, tree) def localContext = ctx.fresh.setTree(tree).setOwner(sym) tree match { case tree: untpd.Ident => typedIdent(tree, pt) @@ -288,5 +297,7 @@ object Erasure { assert(ctx.phase == ctx.erasurePhase.next, ctx.phase) if (tree.isEmpty) tree else adaptToType(tree, pt) } + + override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx } } \ No newline at end of file diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 3060f3951dee..5345b73965e1 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -228,7 +228,7 @@ trait TypeAssigner { val ownType = fn.tpe.widen match { case pt: PolyType => val argTypes = args.tpes - if (sameLength(argTypes, pt.paramNames)) pt.instantiate(args.tpes) + if (sameLength(argTypes, pt.paramNames)) pt.instantiate(argTypes) else errorType(i"wrong number of type parameters for ${fn.tpe}; expected: ${pt.paramNames.length}", tree.pos) case _ => errorType(s"${err.exprStr(fn)} does not take type parameters", tree.pos) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index ed6f3b5d9166..dcd5c67c8649 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -15,37 +15,39 @@ class tests extends CompilerTest { "-pagewidth", "160" ) val twice = List("#runs", "2") + val doErase = List("-Ystop-before:terminal") val posDir = "./tests/pos/" val negDir = "./tests/neg/" val newDir = "./tests/new/" val dotcDir = "./src/dotty/" -/* - @Test def pos_Coder() = compileFile(posDir, "Coder", twice) - @Test def pos_blockescapes() = compileFile(posDir, "blockescapes", twice) - @Test def pos_collections() = compileFile(posDir, "collections", twice) - @Test def pos_functions1() = compileFile(posDir, "functions1", twice) - @Test def pos_implicits1() = compileFile(posDir, "implicits1", twice) - @Test def pos_inferred() = compileFile(posDir, "inferred", twice) - @Test def pos_Patterns() = compileFile(posDir, "Patterns", twice) - @Test def pos_selftypes() = compileFile(posDir, "selftypes", twice) - @Test def pos_varargs() = compileFile(posDir, "varargs", twice) - @Test def pos_opassign() = compileFile(posDir, "opassign", twice) - @Test def pos_typedapply() = compileFile(posDir, "typedapply", twice) - @Test def pos_nameddefaults() = compileFile(posDir, "nameddefaults", twice) - @Test def pos_desugar() = compileFile(posDir, "desugar", twice) - @Test def pos_sigs() = compileFile(posDir, "sigs", twice) - @Test def pos_typers() = compileFile(posDir, "typers", twice) - @Test def pos_typedidents() = compileFile(posDir, "typedIdents", twice) - @Test def pos_assignments() = compileFile(posDir, "assignments", twice) - @Test def pos_packageobject() = compileFile(posDir, "packageobject", twice) - @Test def pos_overloaded() = compileFile(posDir, "overloaded", twice) - @Test def pos_templateParents() = compileFile(posDir, "templateParents", twice) - @Test def pos_structural() = compileFile(posDir, "structural", twice) - @Test def pos_i39 = compileFile(posDir, "i39", twice) - @Test def pos_overloadedAccess = compileFile(posDir, "overloadedAccess", twice) - @Test def pos_approximateUnion = compileFile(posDir, "approximateUnion", twice) -*/ + + @Test def pos_erasure = compileFile(posDir, "erasure", doErase) + @Test def pos_Coder() = compileFile(posDir, "Coder", doErase) + @Test def pos_blockescapes() = compileFile(posDir, "blockescapes", doErase) + @Test def pos_collections() = compileFile(posDir, "collections", doErase) + @Test def pos_functions1() = compileFile(posDir, "functions1", doErase) + @Test def pos_implicits1() = compileFile(posDir, "implicits1", doErase) + @Test def pos_inferred() = compileFile(posDir, "inferred", doErase) + @Test def pos_Patterns() = compileFile(posDir, "Patterns", doErase) + @Test def pos_selftypes() = compileFile(posDir, "selftypes", doErase) + @Test def pos_varargs() = compileFile(posDir, "varargs", doErase) + @Test def pos_opassign() = compileFile(posDir, "opassign", doErase) + @Test def pos_typedapply() = compileFile(posDir, "typedapply", doErase) + @Test def pos_nameddefaults() = compileFile(posDir, "nameddefaults", doErase) + @Test def pos_desugar() = compileFile(posDir, "desugar", doErase) + @Test def pos_sigs() = compileFile(posDir, "sigs", doErase) + @Test def pos_typers() = compileFile(posDir, "typers", doErase) + @Test def pos_typedidents() = compileFile(posDir, "typedIdents", doErase) + @Test def pos_assignments() = compileFile(posDir, "assignments", doErase) + @Test def pos_packageobject() = compileFile(posDir, "packageobject", doErase) + @Test def pos_overloaded() = compileFile(posDir, "overloaded", doErase) + @Test def pos_templateParents() = compileFile(posDir, "templateParents", doErase) + @Test def pos_structural() = compileFile(posDir, "structural", doErase) + @Test def pos_i39 = compileFile(posDir, "i39", doErase) + @Test def pos_overloadedAccess = compileFile(posDir, "overloadedAccess", doErase) + @Test def pos_approximateUnion = compileFile(posDir, "approximateUnion", doErase) + @Test def pos_all = compileFiles(posDir, twice) @Test def new_all = compileFiles(newDir, twice) diff --git a/tests/pos/unions.scala b/tests/pos/unions.scala new file mode 100644 index 000000000000..779d1847e97a --- /dev/null +++ b/tests/pos/unions.scala @@ -0,0 +1,14 @@ +object unions { + + class A { + def f: String = "abc" + } + + class B { + def f: String = "bcd" + } + + val x: A | B = if (true) new A else new B + println(x.f) + +} From 5c1a1498c7215935d466379d7fa85f88f4a001c7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 14:41:09 +0200 Subject: [PATCH 09/13] Maintaining owners during transformations The transformation framework needed to be changed so that contexts passed to transformations have correct owner chains. These owner chins are demanded by the Splitter phase. Note: I eliminated the contexts array in TransformInfo because it interfered with the owner computations. Generally, caching contexts with some phase is best done in Contexts, because withPhase is also used heavily in othre code, not just in Transformers. New phase: Splitter When it is complete, it will make sure that every term Ident and Select node carries a symbol. Right now, all it does is coverting self reference idents to "this"-nodes. --- src/dotty/tools/dotc/Compiler.scala | 2 +- src/dotty/tools/dotc/core/Contexts.scala | 3 + .../transform/PostTyperTransformers.scala | 4 +- src/dotty/tools/dotc/transform/Splitter.scala | 27 +++ .../tools/dotc/transform/TreeTransform.scala | 159 +++++++++--------- 5 files changed, 115 insertions(+), 80 deletions(-) create mode 100644 src/dotty/tools/dotc/transform/Splitter.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 6fd69beb8151..1e8f13578a86 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -21,7 +21,7 @@ class Compiler { List( List(new FrontEnd), List(new LazyValsCreateCompanionObjects, new PatternMatcher), //force separataion between lazyVals and LVCreateCO - List(new LazyValTranformContext().transformer, new TypeTestsCasts), + List(new LazyValTranformContext().transformer, new Splitter, new TypeTestsCasts), List(new Erasure), List(new UncurryTreeTransform) ) diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 8d083b29cdd0..8721bc548466 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -277,6 +277,9 @@ object Contexts { newctx.asInstanceOf[FreshContext] } + final def withOwner(owner: Symbol): Context = + if (owner ne this.owner) fresh.setOwner(owner) else this + final def withMode(mode: Mode): Context = if (mode != this.mode) fresh.setMode(mode) else this diff --git a/src/dotty/tools/dotc/transform/PostTyperTransformers.scala b/src/dotty/tools/dotc/transform/PostTyperTransformers.scala index 14e2cf35d175..25f122cf58c4 100644 --- a/src/dotty/tools/dotc/transform/PostTyperTransformers.scala +++ b/src/dotty/tools/dotc/transform/PostTyperTransformers.scala @@ -48,8 +48,8 @@ object PostTyperTransformers { reorder0(stats) } - override def transformStats(trees: List[tpd.Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[tpd.Tree] = - super.transformStats(reorder(trees)(ctx, info), info, current) + override def transformStats(trees: List[tpd.Tree], exprOwner: Symbol, info: TransformerInfo, current: Int)(implicit ctx: Context): List[tpd.Tree] = + super.transformStats(reorder(trees)(ctx, info), exprOwner, info, current) override def transform(tree: tpd.Tree, info: TransformerInfo, cur: Int)(implicit ctx: Context): tpd.Tree = tree match { case tree: Import => EmptyTree diff --git a/src/dotty/tools/dotc/transform/Splitter.scala b/src/dotty/tools/dotc/transform/Splitter.scala new file mode 100644 index 000000000000..9c01574aae45 --- /dev/null +++ b/src/dotty/tools/dotc/transform/Splitter.scala @@ -0,0 +1,27 @@ +package dotty.tools.dotc +package transform + +import TreeTransforms._ +import ast.Trees._ +import core.Contexts._ +import core.Types._ + +/** This transform makes usre every identifier and select node + * carries a symbol. To do this, certain qualifiers with a union type + * have to be "splitted" with a type test. + * + * For now, only self references are treated. + */ +class Splitter extends TreeTransform { + import ast.tpd._ + + override def name: String = "splitter" + + /** Replace self referencing idents with ThisTypes. */ + override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo) = tree.tpe match { + case ThisType(cls) => + println(s"owner = ${ctx.owner}, context = ${ctx}") + This(cls) withPos tree.pos + case _ => tree + } +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index 6847141991c8..425410ae7ed6 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -3,7 +3,9 @@ package dotty.tools.dotc.transform import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Phases.Phase +import dotty.tools.dotc.core.Symbols.Symbol import dotty.tools.dotc.ast.Trees._ +import dotty.tools.dotc.core.Decorators._ import scala.annotation.tailrec object TreeTransforms { @@ -149,9 +151,7 @@ object TreeTransforms { type Mutator[T] = (TreeTransform, T, Context) => TreeTransform - class TransformerInfo(val transformers: Array[TreeTransform], val nx: NXTransformations, val group:TreeTransformer, val contexts:Array[Context]) { - assert(transformers.size == contexts.size) - } + class TransformerInfo(val transformers: Array[TreeTransform], val nx: NXTransformations, val group:TreeTransformer) /** * This class maintains track of which methods are redefined in MiniPhases and creates execution plans for transformXXX and prepareXXX @@ -431,15 +431,15 @@ object TreeTransforms { val l = result.length var allDone = i < l while (i < l) { - val oldT = result(i) - val newT = mutator(oldT, tree, info.contexts(i)) - allDone = allDone && (newT eq NoTransform) - if (!(oldT eq newT)) { + val oldTransform = result(i) + val newTransform = mutator(oldTransform, tree, ctx.withPhase(oldTransform)) + allDone = allDone && (newTransform eq NoTransform) + if (!(oldTransform eq newTransform)) { if (!transformersCopied) result = result.clone() transformersCopied = true - result(i) = newT - if (!(newT.getClass == oldT.getClass)) { - resultNX = new NXTransformations(resultNX, newT, i, nxCopied) + result(i) = newTransform + if (!(newTransform.getClass == oldTransform.getClass)) { + resultNX = new NXTransformations(resultNX, newTransform, i, nxCopied) nxCopied = true } } @@ -447,7 +447,7 @@ object TreeTransforms { } if (allDone) null else if (!transformersCopied) info - else new TransformerInfo(result, resultNX, info.group, info.contexts) + else new TransformerInfo(result, resultNX, info.group) } val prepForIdent: Mutator[Ident] = (trans, tree, ctx) => trans.prepareForIdent(tree)(ctx) @@ -484,8 +484,7 @@ object TreeTransforms { def transform(t: Tree)(implicit ctx: Context): Tree = { val initialTransformations = transformations - val contexts = initialTransformations.map(tr => ctx.withPhase(tr).ctx) - val info = new TransformerInfo(initialTransformations, new NXTransformations(initialTransformations), this, contexts) + val info = new TransformerInfo(initialTransformations, new NXTransformations(initialTransformations), this) initialTransformations.zipWithIndex.foreach{ case (transform, id) => transform.idx = id @@ -498,8 +497,7 @@ object TreeTransforms { final private[TreeTransforms] def goIdent(tree: Ident, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - - trans.transformIdent(tree)(info.contexts(cur), info) match { + trans.transformIdent(tree)(ctx.withPhase(trans), info) match { case t: Ident => goIdent(t, info.nx.nxTransIdent(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -510,7 +508,7 @@ object TreeTransforms { final private[TreeTransforms] def goSelect(tree: Select, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformSelect(tree)(info.contexts(cur), info) match { + trans.transformSelect(tree)(ctx.withPhase(trans), info) match { case t: Select => goSelect(t, info.nx.nxTransSelect(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -521,7 +519,7 @@ object TreeTransforms { final private[TreeTransforms] def goThis(tree: This, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformThis(tree)(info.contexts(cur), info) match { + trans.transformThis(tree)(ctx.withPhase(trans), info) match { case t: This => goThis(t, info.nx.nxTransThis(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -532,7 +530,7 @@ object TreeTransforms { final private[TreeTransforms] def goSuper(tree: Super, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformSuper(tree)(info.contexts(cur), info) match { + trans.transformSuper(tree)(ctx.withPhase(trans), info) match { case t: Super => goSuper(t, info.nx.nxTransSuper(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -543,7 +541,7 @@ object TreeTransforms { final private[TreeTransforms] def goApply(tree: Apply, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformApply(tree)(info.contexts(cur), info) match { + trans.transformApply(tree)(ctx.withPhase(trans), info) match { case t: Apply => goApply(t, info.nx.nxTransApply(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -554,7 +552,7 @@ object TreeTransforms { final private[TreeTransforms] def goTypeApply(tree: TypeApply, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformTypeApply(tree)(info.contexts(cur), info) match { + trans.transformTypeApply(tree)(ctx.withPhase(trans), info) match { case t: TypeApply => goTypeApply(t, info.nx.nxTransTypeApply(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -565,7 +563,7 @@ object TreeTransforms { final private[TreeTransforms] def goNew(tree: New, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformNew(tree)(info.contexts(cur), info) match { + trans.transformNew(tree)(ctx.withPhase(trans), info) match { case t: New => goNew(t, info.nx.nxTransNew(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -576,7 +574,7 @@ object TreeTransforms { final private[TreeTransforms] def goPair(tree: Pair, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformPair(tree)(info.contexts(cur), info) match { + trans.transformPair(tree)(ctx.withPhase(trans), info) match { case t: Pair => goPair(t, info.nx.nxTransPair(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -587,7 +585,7 @@ object TreeTransforms { final private[TreeTransforms] def goTyped(tree: Typed, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformTyped(tree)(info.contexts(cur), info) match { + trans.transformTyped(tree)(ctx.withPhase(trans), info) match { case t: Typed => goTyped(t, info.nx.nxTransTyped(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -598,7 +596,7 @@ object TreeTransforms { final private[TreeTransforms] def goAssign(tree: Assign, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformAssign(tree)(info.contexts(cur), info) match { + trans.transformAssign(tree)(ctx.withPhase(trans), info) match { case t: Assign => goAssign(t, info.nx.nxTransAssign(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -609,7 +607,7 @@ object TreeTransforms { final private[TreeTransforms] def goLiteral(tree: Literal, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformLiteral(tree)(info.contexts(cur), info) match { + trans.transformLiteral(tree)(ctx.withPhase(trans), info) match { case t: Literal => goLiteral(t, info.nx.nxTransLiteral(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -620,7 +618,7 @@ object TreeTransforms { final private[TreeTransforms] def goBlock(tree: Block, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformBlock(tree)(info.contexts(cur), info) match { + trans.transformBlock(tree)(ctx.withPhase(trans), info) match { case t: Block => goBlock(t, info.nx.nxTransBlock(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -631,7 +629,7 @@ object TreeTransforms { final private[TreeTransforms] def goIf(tree: If, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformIf(tree)(info.contexts(cur), info) match { + trans.transformIf(tree)(ctx.withPhase(trans), info) match { case t: If => goIf(t, info.nx.nxTransIf(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -642,7 +640,7 @@ object TreeTransforms { final private[TreeTransforms] def goClosure(tree: Closure, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformClosure(tree)(info.contexts(cur), info) match { + trans.transformClosure(tree)(ctx.withPhase(trans), info) match { case t: Closure => goClosure(t, info.nx.nxTransClosure(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -653,7 +651,7 @@ object TreeTransforms { final private[TreeTransforms] def goMatch(tree: Match, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformMatch(tree)(info.contexts(cur), info) match { + trans.transformMatch(tree)(ctx.withPhase(trans), info) match { case t: Match => goMatch(t, info.nx.nxTransMatch(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -664,7 +662,7 @@ object TreeTransforms { final private[TreeTransforms] def goCaseDef(tree: CaseDef, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformCaseDef(tree)(info.contexts(cur), info) match { + trans.transformCaseDef(tree)(ctx.withPhase(trans), info) match { case t: CaseDef => goCaseDef(t, info.nx.nxTransCaseDef(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -675,7 +673,7 @@ object TreeTransforms { final private[TreeTransforms] def goReturn(tree: Return, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformReturn(tree)(info.contexts(cur), info) match { + trans.transformReturn(tree)(ctx.withPhase(trans), info) match { case t: Return => goReturn(t, info.nx.nxTransReturn(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -686,7 +684,7 @@ object TreeTransforms { final private[TreeTransforms] def goTry(tree: Try, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformTry(tree)(info.contexts(cur), info) match { + trans.transformTry(tree)(ctx.withPhase(trans), info) match { case t: Try => goTry(t, info.nx.nxTransTry(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -697,7 +695,7 @@ object TreeTransforms { final private[TreeTransforms] def goThrow(tree: Throw, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformThrow(tree)(info.contexts(cur), info) match { + trans.transformThrow(tree)(ctx.withPhase(trans), info) match { case t: Throw => goThrow(t, info.nx.nxTransThrow(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -708,7 +706,7 @@ object TreeTransforms { final private[TreeTransforms] def goSeqLiteral(tree: SeqLiteral, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformSeqLiteral(tree)(info.contexts(cur), info) match { + trans.transformSeqLiteral(tree)(ctx.withPhase(trans), info) match { case t: SeqLiteral => goSeqLiteral(t, info.nx.nxTransSeqLiteral(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -719,7 +717,7 @@ object TreeTransforms { final private[TreeTransforms] def goTypeTree(tree: TypeTree, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformTypeTree(tree)(info.contexts(cur), info) match { + trans.transformTypeTree(tree)(ctx.withPhase(trans), info) match { case t: TypeTree => goTypeTree(t, info.nx.nxTransTypeTree(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -730,7 +728,7 @@ object TreeTransforms { final private[TreeTransforms] def goSelectFromTypeTree(tree: SelectFromTypeTree, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformSelectFromTypeTree(tree)(info.contexts(cur), info) match { + trans.transformSelectFromTypeTree(tree)(ctx.withPhase(trans), info) match { case t: SelectFromTypeTree => goSelectFromTypeTree(t, info.nx.nxTransSelectFromTypeTree(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -741,7 +739,7 @@ object TreeTransforms { final private[TreeTransforms] def goBind(tree: Bind, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformBind(tree)(info.contexts(cur), info) match { + trans.transformBind(tree)(ctx.withPhase(trans), info) match { case t: Bind => goBind(t, info.nx.nxTransBind(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -752,7 +750,7 @@ object TreeTransforms { final private[TreeTransforms] def goAlternative(tree: Alternative, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformAlternative(tree)(info.contexts(cur), info) match { + trans.transformAlternative(tree)(ctx.withPhase(trans), info) match { case t: Alternative => goAlternative(t, info.nx.nxTransAlternative(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -763,7 +761,7 @@ object TreeTransforms { final private[TreeTransforms] def goValDef(tree: ValDef, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformValDef(tree)(info.contexts(cur), info) match { + trans.transformValDef(tree)(ctx.withPhase(trans), info) match { case t: ValDef => goValDef(t, info.nx.nxTransValDef(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -774,7 +772,7 @@ object TreeTransforms { final private[TreeTransforms] def goDefDef(tree: DefDef, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformDefDef(tree)(info.contexts(cur), info) match { + trans.transformDefDef(tree)(ctx.withPhase(trans), info) match { case t: DefDef => goDefDef(t, info.nx.nxTransDefDef(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -785,7 +783,7 @@ object TreeTransforms { final private[TreeTransforms] def goUnApply(tree: UnApply, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformUnApply(tree)(info.contexts(cur), info) match { + trans.transformUnApply(tree)(ctx.withPhase(trans), info) match { case t: UnApply => goUnApply(t, info.nx.nxTransUnApply(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -796,7 +794,7 @@ object TreeTransforms { final private[TreeTransforms] def goTypeDef(tree: TypeDef, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformTypeDef(tree)(info.contexts(cur), info) match { + trans.transformTypeDef(tree)(ctx.withPhase(trans), info) match { case t: TypeDef => goTypeDef(t, info.nx.nxTransTypeDef(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -807,7 +805,7 @@ object TreeTransforms { final private[TreeTransforms] def goTemplate(tree: Template, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformTemplate(tree)(info.contexts(cur), info) match { + trans.transformTemplate(tree)(ctx.withPhase(trans), info) match { case t: Template => goTemplate(t, info.nx.nxTransTemplate(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -818,7 +816,7 @@ object TreeTransforms { final private[TreeTransforms] def goPackageDef(tree: PackageDef, cur: Int)(implicit ctx: Context, info: TransformerInfo): Tree = { if (cur < info.transformers.length) { val trans = info.transformers(cur) - trans.transformPackageDef(tree)(info.contexts(cur), info) match { + trans.transformPackageDef(tree)(ctx.withPhase(trans), info) match { case t: PackageDef => goPackageDef(t, info.nx.nxTransPackageDef(cur + 1)) case t => transformSingle(t, cur + 1) } @@ -863,9 +861,7 @@ object TreeTransforms { case tree: UnApply => goUnApply(tree, info.nx.nxTransUnApply(cur)) case tree: Template => goTemplate(tree, info.nx.nxTransTemplate(cur)) case tree: PackageDef => goPackageDef(tree, info.nx.nxTransPackageDef(cur)) - case Thicket(trees) if trees != Nil => - val trees1 = transformL(trees.asInstanceOf[List[tpd.Tree]], info, cur) - if (trees1 eq trees) tree else Thicket(trees1) + case Thicket(trees) => cpy.Thicket(tree, transformTrees(trees, info, cur)) case tree => tree } @@ -876,7 +872,9 @@ object TreeTransforms { case tree => goUnamed(tree, cur) } - final private[TreeTransforms] def transformNameTree(tree: NameTree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree = + def localContext(owner: Symbol)(implicit ctx: Context) = ctx.fresh.setOwner(owner) + + final private[TreeTransforms] def transformNamed(tree: NameTree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree = tree match { case tree: Ident => implicit val mutatedInfo = mutateTransformers(info, prepForIdent, info.nx.nxPrepIdent, tree, cur) @@ -907,25 +905,27 @@ object TreeTransforms { implicit val mutatedInfo = mutateTransformers(info, prepForValDef, info.nx.nxPrepValDef, tree, cur) if (mutatedInfo eq null) tree else { - val tpt = transform(tree.tpt, mutatedInfo, cur) - val rhs = transform(tree.rhs, mutatedInfo, cur) + val nestedCtx = if (tree.symbol.exists) localContext(tree.symbol) else ctx + val tpt = transform(tree.tpt, mutatedInfo, cur)(nestedCtx) + val rhs = transform(tree.rhs, mutatedInfo, cur)(nestedCtx) goValDef(cpy.ValDef(tree, tree.mods, tree.name, tpt, rhs), mutatedInfo.nx.nxTransValDef(cur)) } case tree: DefDef => implicit val mutatedInfo = mutateTransformers(info, prepForDefDef, info.nx.nxPrepDefDef, tree, cur) if (mutatedInfo eq null) tree else { - val tparams = transformSubL(tree.tparams, mutatedInfo, cur) - val vparams = tree.vparamss.mapConserve(x => transformSubL(x, mutatedInfo, cur)) - val tpt = transform(tree.tpt, mutatedInfo, cur) - val rhs = transform(tree.rhs, mutatedInfo, cur) + val nestedCtx = localContext(tree.symbol) + val tparams = transformSubTrees(tree.tparams, mutatedInfo, cur)(nestedCtx) + val vparams = tree.vparamss.mapConserve(x => transformSubTrees(x, mutatedInfo, cur)(nestedCtx)) + val tpt = transform(tree.tpt, mutatedInfo, cur)(nestedCtx) + val rhs = transform(tree.rhs, mutatedInfo, cur)(nestedCtx) goDefDef(cpy.DefDef(tree, tree.mods, tree.name, tparams, vparams, tpt, rhs), mutatedInfo.nx.nxTransDefDef(cur)) } case tree: TypeDef => implicit val mutatedInfo = mutateTransformers(info, prepForTypeDef, info.nx.nxPrepTypeDef, tree, cur) if (mutatedInfo eq null) tree else { - val rhs = transform(tree.rhs, mutatedInfo, cur) + val rhs = transform(tree.rhs, mutatedInfo, cur)(localContext(tree.symbol)) goTypeDef(cpy.TypeDef(tree, tree.mods, tree.name, rhs, tree.tparams), mutatedInfo.nx.nxTransTypeDef(cur)) } case _ => @@ -950,7 +950,7 @@ object TreeTransforms { if (mutatedInfo eq null) tree else { val fun = transform(tree.fun, mutatedInfo, cur) - val args = transformSubL(tree.args, mutatedInfo, cur) + val args = transformSubTrees(tree.args, mutatedInfo, cur) goApply(cpy.Apply(tree, fun, args), mutatedInfo.nx.nxTransApply(cur)) } case tree: TypeApply => @@ -958,7 +958,7 @@ object TreeTransforms { if (mutatedInfo eq null) tree else { val fun = transform(tree.fun, mutatedInfo, cur) - val args = transformL(tree.args, mutatedInfo, cur) + val args = transformTrees(tree.args, mutatedInfo, cur) goTypeApply(cpy.TypeApply(tree, fun, args), mutatedInfo.nx.nxTransTypeApply(cur)) } case tree: Literal => @@ -1000,7 +1000,7 @@ object TreeTransforms { implicit val mutatedInfo = mutateTransformers(info, prepForBlock, info.nx.nxPrepBlock, tree, cur) if (mutatedInfo eq null) tree else { - val stats = transformStats(tree.stats, mutatedInfo, cur) + val stats = transformStats(tree.stats, ctx.owner, mutatedInfo, cur) val expr = transform(tree.expr, mutatedInfo, cur) goBlock(cpy.Block(tree, stats, expr), mutatedInfo.nx.nxTransBlock(cur)) } @@ -1017,7 +1017,7 @@ object TreeTransforms { implicit val mutatedInfo = mutateTransformers(info, prepForClosure, info.nx.nxPrepClosure, tree, cur) if (mutatedInfo eq null) tree else { - val env = transformL(tree.env, mutatedInfo, cur) + val env = transformTrees(tree.env, mutatedInfo, cur) val meth = transform(tree.meth, mutatedInfo, cur) val tpt = transform(tree.tpt, mutatedInfo, cur) goClosure(cpy.Closure(tree, env, meth, tpt), mutatedInfo.nx.nxTransClosure(cur)) @@ -1027,7 +1027,7 @@ object TreeTransforms { if (mutatedInfo eq null) tree else { val selector = transform(tree.selector, mutatedInfo, cur) - val cases = transformSubL(tree.cases, mutatedInfo, cur) + val cases = transformSubTrees(tree.cases, mutatedInfo, cur) goMatch(cpy.Match(tree, selector, cases), mutatedInfo.nx.nxTransMatch(cur)) } case tree: CaseDef => @@ -1067,7 +1067,7 @@ object TreeTransforms { implicit val mutatedInfo = mutateTransformers(info, prepForSeqLiteral, info.nx.nxPrepSeqLiteral, tree, cur) if (mutatedInfo eq null) tree else { - val elems = transformL(tree.elems, mutatedInfo, cur) + val elems = transformTrees(tree.elems, mutatedInfo, cur) goSeqLiteral(cpy.SeqLiteral(tree, elems), mutatedInfo.nx.nxTransLiteral(cur)) } case tree: TypeTree => @@ -1081,7 +1081,7 @@ object TreeTransforms { implicit val mutatedInfo = mutateTransformers(info, prepForAlternative, info.nx.nxPrepAlternative, tree, cur) if (mutatedInfo eq null) tree else { - val trees = transformL(tree.trees, mutatedInfo, cur) + val trees = transformTrees(tree.trees, mutatedInfo, cur) goAlternative(cpy.Alternative(tree, trees), mutatedInfo.nx.nxTransAlternative(cur)) } case tree: UnApply => @@ -1089,8 +1089,8 @@ object TreeTransforms { if (mutatedInfo eq null) tree else { val fun = transform(tree.fun, mutatedInfo, cur) - val implicits = transformL(tree.implicits, mutatedInfo, cur) - val patterns = transformL(tree.patterns, mutatedInfo, cur) + val implicits = transformTrees(tree.implicits, mutatedInfo, cur) + val patterns = transformTrees(tree.patterns, mutatedInfo, cur) goUnApply(cpy.UnApply(tree, fun, implicits, patterns), mutatedInfo.nx.nxTransUnApply(cur)) } case tree: Template => @@ -1098,29 +1098,28 @@ object TreeTransforms { if (mutatedInfo eq null) tree else { val constr = transformSub(tree.constr, mutatedInfo, cur) - val parents = transformL(tree.parents, mutatedInfo, cur) + val parents = transformTrees(tree.parents, mutatedInfo, cur) val self = transformSub(tree.self, mutatedInfo, cur) - val body = transformStats(tree.body, mutatedInfo, cur) + val body = transformStats(tree.body, tree.symbol, mutatedInfo, cur) goTemplate(cpy.Template(tree, constr, parents, self, body), mutatedInfo.nx.nxTransTemplate(cur)) } case tree: PackageDef => implicit val mutatedInfo = mutateTransformers(info, prepForPackageDef, info.nx.nxPrepPackageDef, tree, cur) if (mutatedInfo eq null) tree else { + val nestedCtx = localContext(tree.symbol) val pid = transformSub(tree.pid, mutatedInfo, cur) - val stats = transformStats(tree.stats, mutatedInfo, cur) + val stats = transformStats(tree.stats, tree.symbol, mutatedInfo, cur)(nestedCtx) goPackageDef(cpy.PackageDef(tree, pid, stats), mutatedInfo.nx.nxTransPackageDef(cur)) } - case Thicket(trees) if trees != Nil => - val trees1 = transformL(trees.asInstanceOf[List[tpd.Tree]], info, cur) - if (trees1 eq trees) tree else Thicket(trees1) + case Thicket(trees) => cpy.Thicket(tree, transformTrees(trees, info, cur)) case tree => tree } def transform(tree: Tree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree = { tree match { //split one big match into 2 smaller ones - case tree: NameTree => transformNameTree(tree, info, cur) + case tree: NameTree => transformNamed(tree, info, cur) case tree => transformUnnamed(tree, info, cur) } } @@ -1134,20 +1133,26 @@ object TreeTransforms { } else trees } - def transformStats(trees: List[Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tree] = { + def transformStats(trees: List[Tree], exprOwner: Symbol, info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tree] = { val newInfo = mutateTransformers(info, prepForStats, info.nx.nxPrepStats, trees, current) - val newTrees = transformL(trees, newInfo, current)(ctx) - flatten(goStats(newTrees, newInfo.nx.nxTransStats(current))(ctx, newInfo)) + val exprCtx = ctx.withOwner(exprOwner) + def transformStat(stat: Tree): Tree = stat match { + case _: Import | _: DefTree => transform(stat, info, current) + case Thicket(stats) => cpy.Thicket(stat, stats mapConserve transformStat) + case _ => transform(stat, info, current)(exprCtx) + } + val newTrees = flatten(trees.mapconserve(transformStat)) + goStats(newTrees, newInfo.nx.nxTransStats(current))(ctx, newInfo) } - def transformL(trees: List[Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tree] = + def transformTrees(trees: List[Tree], info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tree] = flatten(trees mapConserve (x => transform(x, info, current))) def transformSub[Tr <: Tree](tree: Tr, info: TransformerInfo, current: Int)(implicit ctx: Context): Tr = transform(tree, info, current).asInstanceOf[Tr] - def transformSubL[Tr <: Tree](trees: List[Tr], info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tr] = - transformL(trees, info, current)(ctx).asInstanceOf[List[Tr]] + def transformSubTrees[Tr <: Tree](trees: List[Tr], info: TransformerInfo, current: Int)(implicit ctx: Context): List[Tr] = + transformTrees(trees, info, current)(ctx).asInstanceOf[List[Tr]] } } From cac8c752b626bc0a5f872572f8ec07274f5e9e0e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 10:28:23 +0200 Subject: [PATCH 10/13] Added implementation of TypeTestsCasts#box --- src/dotty/tools/dotc/transform/TypeTestsCasts.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index 48a377c020be..54f72c20c9cd 100644 --- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -13,6 +13,7 @@ import core.StdNames._ import core.transform.Erasure.isUnboundedGeneric import typer.ErrorReporting._ import ast.Trees._ +import Erasure.Boxing.box /** This transform normalizes type tests and type casts. * Any remaining type tests @@ -23,8 +24,6 @@ import ast.Trees._ class TypeTestsCasts extends TreeTransform { import ast.tpd._ - def box(tree: Tree): Tree = ??? - override def name: String = "typeTestsCasts" override def transformTypeApply(tree: TypeApply)(implicit ctx: Context, info: TransformerInfo): Tree = ctx.traceIndented(s"transforming ${tree.show}", show = true) { From d173cc048ebdbff30f6537f207118fc5717b8787 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 14:45:51 +0200 Subject: [PATCH 11/13] Renaming clear->setNew clear is wrong. E.g. clearTyperState does not clear the typerstate at all. It installs a fresh (i.e. cloned) copy of the previous one. clearScope is also wrong; it installs a new scope, does not clear the current one. --- src/dotty/tools/dotc/core/Contexts.scala | 4 ++-- src/dotty/tools/dotc/typer/Implicits.scala | 4 ++-- src/dotty/tools/dotc/typer/Inferencing.scala | 2 +- src/dotty/tools/dotc/typer/Namer.scala | 6 +++--- src/dotty/tools/dotc/typer/Typer.scala | 10 +++++----- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 8721bc548466..4ccc9be73e2f 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -316,7 +316,7 @@ object Contexts { def setPeriod(period: Period): this.type = { this.period = period; this } def setMode(mode: Mode): this.type = { this.mode = mode; this } def setTyperState(typerState: TyperState): this.type = { this.typerState = typerState; this } - def clearTyperState: this.type = setTyperState(typerState.fresh(isCommittable = true)) + def setNewTyperState: this.type = setTyperState(typerState.fresh(isCommittable = true)) def setExploreTyperState: this.type = setTyperState(typerState.fresh(isCommittable = false)) def setPrinterFn(printer: Context => Printer): this.type = { this.printerFn = printer; this } def setOwner(owner: Symbol): this.type = { assert(owner != NoSymbol); this.owner = owner; this } @@ -324,7 +324,7 @@ object Contexts { def setCompilationUnit(compilationUnit: CompilationUnit): this.type = { this.compilationUnit = compilationUnit; this } def setTree(tree: Tree[_ >: Untyped]): this.type = { this.tree = tree; this } def setScope(scope: Scope): this.type = { this.scope = scope; this } - def clearScope: this.type = { this.scope = newScope; this } + def setNewScope: this.type = { this.scope = newScope; this } def setTypeAssigner(typeAssigner: TypeAssigner): this.type = { this.typeAssigner = typeAssigner; this } def setTyper(typer: Typer): this.type = { this.scope = typer.scope; setTypeAssigner(typer) } def setImportInfo(importInfo: ImportInfo): this.type = { this.importInfo = importInfo; this } diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 8990d21a24d0..db549b2d4d48 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -457,7 +457,7 @@ trait Implicits { self: Typer => pt) val generated1 = adapt(generated, pt) lazy val shadowing = - typed(untpd.Ident(ref.name) withPos pos.toSynthetic, funProto)(nestedContext.clearTyperState) + typed(untpd.Ident(ref.name) withPos pos.toSynthetic, funProto)(nestedContext.setNewTyperState) def refMatches(shadowing: Tree): Boolean = ref.symbol == closureBody(shadowing).symbol || { shadowing match { @@ -485,7 +485,7 @@ trait Implicits { self: Typer => val history = ctx.searchHistory nest wildProto val result = if (history eq ctx.searchHistory) divergingImplicit(ref) - else typedImplicit(ref)(nestedContext.clearTyperState.setSearchHistory(history)) + else typedImplicit(ref)(nestedContext.setNewTyperState.setSearchHistory(history)) result match { case fail: SearchFailure => rankImplicits(pending1, acc) diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 9c4ce232e344..173ac3aeba82 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -30,7 +30,7 @@ trait Inferencing { this: Checking => * Variables that are successfully minimized do not count as uninstantiated. */ def isFullyDefined(tp: Type, force: ForceDegree.Value)(implicit ctx: Context): Boolean = { - val nestedCtx = ctx.fresh.clearTyperState + val nestedCtx = ctx.fresh.setNewTyperState val result = new IsFullyDefinedAccumulator(force)(nestedCtx).process(tp) if (result) nestedCtx.typerState.commit() result diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index e81949f05e4e..d0e78185f85a 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -292,7 +292,7 @@ class Namer { typer: Typer => /** A new context for the interior of a class */ def inClassContext(selfInfo: DotClass /* Should be Type | Symbol*/)(implicit ctx: Context): Context = { - val localCtx: Context = ctx.fresh.clearScope + val localCtx: Context = ctx.fresh.setNewScope selfInfo match { case sym: Symbol if sym.exists && sym.name != nme.WILDCARD => localCtx.scope.asInstanceOf[MutableScope].enter(sym) @@ -385,14 +385,14 @@ class Namer { typer: Typer => private def typeSig(sym: Symbol): Type = original match { case original: ValDef => if (sym is Module) moduleValSig(sym) - else valOrDefDefSig(original, sym, Nil, identity)(localContext(sym).clearScope) + else valOrDefDefSig(original, sym, Nil, identity)(localContext(sym).setNewScope) case original: DefDef => val typer1 = new Typer nestedTyper(sym) = typer1 typer1.defDefSig(original, sym)(localContext(sym).setTyper(typer1)) case original: TypeDef => assert(!original.isClassDef) - typeDefSig(original, sym)(localContext(sym).clearScope) + typeDefSig(original, sym)(localContext(sym).setNewScope) case imp: Import => try { val expr1 = typedAheadExpr(imp.expr, AnySelectionProto) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 87bc643a3c31..b72cd0fa8c3d 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -587,7 +587,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit assignType(cpy.CaseDef(tree, pat, guard1, body1), body1) } val doCase: () => CaseDef = - () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.clearScope) + () => caseRest(typedPattern(tree.pat, selType))(ctx.fresh.setNewScope) (doCase /: gadtSyms)((op, tsym) => tsym.withGADTFlexType(op))() } @@ -881,13 +881,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case tree: untpd.Bind => typedBind(tree, pt) case tree: untpd.ValDef => if (tree.isEmpty) tpd.EmptyValDef - else typedValDef(tree, sym)(localContext.clearScope) + else typedValDef(tree, sym)(localContext.setNewScope) case tree: untpd.DefDef => val typer1 = nestedTyper.remove(sym).get typer1.typedDefDef(tree, sym)(localContext.setTyper(typer1)) case tree: untpd.TypeDef => if (tree.isClassDef) typedClassDef(tree, sym.asClass)(localContext) - else typedTypeDef(tree, sym)(localContext.clearScope) + else typedTypeDef(tree, sym)(localContext.setNewScope) case _ => typedUnadapted(desugar(tree), pt) } } @@ -909,7 +909,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case tree: untpd.Typed => typedTyped(tree, pt) case tree: untpd.NamedArg => typedNamedArg(tree, pt) case tree: untpd.Assign => typedAssign(tree, pt) - case tree: untpd.Block => typedBlock(desugar.block(tree), pt)(ctx.fresh.clearScope) + case tree: untpd.Block => typedBlock(desugar.block(tree), pt)(ctx.fresh.setNewScope) case tree: untpd.If => typedIf(tree, pt) case tree: untpd.Function => typedFunction(tree, pt) case tree: untpd.Closure => typedClosure(tree, pt) @@ -992,7 +992,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit typed(tree, pt)(ctx addMode Mode.Pattern) def tryEither[T](op: Context => T)(fallBack: (T, TyperState) => T)(implicit ctx: Context) = { - val nestedCtx = ctx.fresh.clearTyperState + val nestedCtx = ctx.fresh.setNewTyperState val result = op(nestedCtx) if (nestedCtx.reporter.hasErrors) fallBack(result, nestedCtx.typerState) From 318db7dc616a659687d95380efa16159cfaeb984 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 31 Mar 2014 14:53:44 +0200 Subject: [PATCH 12/13] Memoizing Context#withPhase withPhase operations in contexts are now memoized. Conflicts: src/dotty/tools/dotc/core/Contexts.scala --- src/dotty/tools/dotc/core/Contexts.scala | 51 +++++++++++++++--------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 4ccc9be73e2f..b0214a631e8b 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -181,6 +181,30 @@ object Contexts { protected def searchHistory_= (searchHistory: SearchHistory) = _searchHistory = searchHistory def searchHistory: SearchHistory = _searchHistory + private var phasedCtx: Context = _ + private var phasedCtxs: Array[Context] = _ + + + /** This context at given phase. + * This method will always return a phase period equal to phaseId, thus will never return squashed phases + */ + final def withPhase(phaseId: PhaseId): Context = { + if (this.phaseId == phaseId) this + else if (phasedCtx.phaseId == phaseId) phasedCtx + else if (phasedCtxs != null && phasedCtxs(phaseId) != null) phasedCtxs(phaseId) + else { + val ctx1 = fresh.setPhase(phaseId) + if (phasedCtx eq this) phasedCtx = ctx1 + else { + if (phasedCtxs == null) phasedCtxs = new Array[Context](base.phases.length) + phasedCtxs(phaseId) = ctx1 + } + ctx1 + } + } + + final def withPhase(phase: Phase): Context = + withPhase(phase.id) /** If -Ydebug is on, the top of the stack trace where this context * was created, otherwise `null`. */ @@ -266,16 +290,16 @@ object Contexts { } */ - /** A fresh clone of this context. */ - def fresh: FreshContext = { - val newctx: Context = super.clone.asInstanceOf[FreshContext] - newctx.outer = this - newctx.implicitsCache = null - newctx.setCreationTrace() - // Dotty deviation: Scala2x allows access to private members implicitCache and setCreationTrace - // even from a subclass prefix. Dotty (and Java) do not. It's confirmed as a bug in Scala2x. - newctx.asInstanceOf[FreshContext] + protected def init(outer: Context): this.type = { + this.outer = outer + this.implicitsCache = null + this.phasedCtx = this + this.phasedCtxs = null + setCreationTrace() + this } + /** A fresh clone of this context. */ + def fresh: FreshContext = clone.asInstanceOf[FreshContext].init(this) final def withOwner(owner: Symbol): Context = if (owner ne this.owner) fresh.setOwner(owner) else this @@ -283,15 +307,6 @@ object Contexts { final def withMode(mode: Mode): Context = if (mode != this.mode) fresh.setMode(mode) else this - /** - * This method will always return a phase period equal to phaseId, thus will never return squashed phases - */ - final def withPhase(phaseId: PhaseId): Context = - if (this.phaseId == phaseId) this else fresh.setPhase(phaseId) - final def withPhase(phase: Phase): Context = - if (this.period == phase.period) this else fresh.setPhase(phase) - - final def addMode(mode: Mode): Context = withMode(this.mode | mode) final def maskMode(mode: Mode): Context = withMode(this.mode & mode) final def retractMode(mode: Mode): Context = withMode(this.mode &~ mode) From fb9a9e65c941a7b840baaa32641818d32b45b5b7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 16:31:01 +0200 Subject: [PATCH 13/13] Factored re-typing logic into seperate ReTyper class Refactored re-typing logic from erasure into seperate ReTyper class. Another candidate subclass of ReTyper is a future TreeChecker. --- src/dotty/tools/dotc/transform/Erasure.scala | 40 ++--------- src/dotty/tools/dotc/typer/ReTyper.scala | 56 +++++++++++++++ src/dotty/tools/dotc/typer/Typer.scala | 74 +++++++++++--------- 3 files changed, 101 insertions(+), 69 deletions(-) create mode 100644 src/dotty/tools/dotc/typer/ReTyper.scala diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index b403d4e66fa8..d4156e1d7645 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -158,27 +158,18 @@ object Erasure { cast(tree, pt) } - class Typer extends typer.Typer with NoChecking { + class Typer extends typer.ReTyper with NoChecking { import Boxing._ - def erasedType(tree: untpd.Tree)(implicit ctx: Context): Type = - erasure(tree.tpe.asInstanceOf[Type]) + def erasedType(tree: untpd.Tree)(implicit ctx: Context): Type = erasure(tree.typeOpt) - private def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = { + override def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = { assert(tree.hasType) val erased = erasedType(tree)(ctx.withPhase(ctx.erasurePhase)) ctx.log(s"promoting ${tree.show}: ${erased.showWithUnderlying()}") tree.withType(erased) } - override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = { - val tree1 = promote(tree) - tree1.tpe match { - case ThisType(cls) => This(cls) withPos tree.pos - case _ => tree1 - } - } - /** Type check select nodes, applying the following rewritings exhaustively * on selections `e.m`. * @@ -263,12 +254,8 @@ object Erasure { super.typedDefDef(ddef1, sym) } - override def typedClassDef(cdef: untpd.TypeDef, sym: ClassSymbol)(implicit ctx: Context) = { - val TypeDef(mods, name, impl @ Template(constr, parents, self, body)) = cdef - val cdef1 = untpd.cpy.TypeDef(cdef, mods, name, - untpd.cpy.Template(impl, constr, parents, untpd.EmptyValDef, body)) - super.typedClassDef(cdef1, sym) - } + override def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context) = + EmptyTree /* override def transformStats(stats: List[Tree], exprOwner: Symbol)(implicit ctx: Context) = { @@ -276,28 +263,11 @@ object Erasure { if (ctx.owner.isClass) addBridges(stats1) else stats1 } */ - override def typedNamed(tree: untpd.NameTree, pt: Type)(implicit ctx: Context): Tree = { - if (tree eq untpd.EmptyValDef) return tpd.EmptyValDef - assert(tree.hasType, tree.show) - val sym = tree.symbol - def localContext = ctx.fresh.setTree(tree).setOwner(sym) - tree match { - case tree: untpd.Ident => typedIdent(tree, pt) - case tree: untpd.Select => typedSelect(tree, pt) - case tree: untpd.ValDef => typedValDef(tree, sym)(localContext) - case tree: untpd.DefDef => typedDefDef(tree, sym)(localContext) - case tree: untpd.TypeDef => - if (tree.isClassDef) typedClassDef(tree, sym.asClass)(localContext) - else EmptyTree - } - } override def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = ctx.traceIndented(i"adapting ${tree.showSummary}: ${tree.tpe} to $pt", show = true) { assert(ctx.phase == ctx.erasurePhase.next, ctx.phase) if (tree.isEmpty) tree else adaptToType(tree, pt) } - - override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx } } \ No newline at end of file diff --git a/src/dotty/tools/dotc/typer/ReTyper.scala b/src/dotty/tools/dotc/typer/ReTyper.scala new file mode 100644 index 000000000000..896dbba7dc2f --- /dev/null +++ b/src/dotty/tools/dotc/typer/ReTyper.scala @@ -0,0 +1,56 @@ +package dotty.tools.dotc +package typer + +import core.Contexts._ +import core.Types._ +import core.Symbols.Symbol +import typer.ProtoTypes._ +import ast.{tpd, untpd} +import ast.Trees._ + +/** A version of Typer that keeps all symbols defined and referenced in a + * previously typed tree. + * + * All definition nodes keep their symbols. All leaf nodes for idents, selects, + * and TypeTrees keep their types. Indexing is a no-op. + * + * Otherwise, everything is as in Typer. + */ +class ReTyper extends Typer { + import tpd._ + + protected def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = { + assert(tree.hasType) + tree.withType(tree.typeOpt) + } + + override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = + promote(tree) + + override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { + assert(tree.hasType) + val qual1 = typed(tree.qualifier, AnySelectionProto) + untpd.cpy.Select(tree, qual1, tree.name).withType(tree.typeOpt) + } + + override def typedSelectFromTypeTree(tree: untpd.SelectFromTypeTree, pt: Type)(implicit ctx: Context): SelectFromTypeTree = { + assert(tree.hasType) + val qual1 = typed(tree.qualifier, AnySelectionProto) + untpd.cpy.SelectFromTypeTree(tree, qual1, tree.name).withType(tree.typeOpt) + } + + override def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = + promote(tree) + + override def typedBind(tree: untpd.Bind, pt: Type)(implicit ctx: Context): Bind = { + assert(tree.hasType) + val body1 = typed(tree.body, pt) + untpd.cpy.Bind(tree, tree.name, body1).withType(tree.typeOpt) + } + + override def retrieveSym(tree: untpd.Tree)(implicit ctx: Context): Symbol = tree.symbol + + override def localTyper(sym: Symbol) = this + + override def index(trees: List[untpd.Tree])(implicit ctx: Context) = ctx +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index b72cd0fa8c3d..c2488f68cfdb 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -775,7 +775,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit //todo: make sure dependent method types do not depend on implicits or by-name params } - def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): TypeDef = track("typedTypeDef") { + def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): Tree = track("typedTypeDef") { val TypeDef(mods, name, rhs) = tdef val mods1 = typedModifiers(mods) val _ = typedType(rhs) // unused, typecheck only to remove from typedTree @@ -858,40 +858,26 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def typedAsFunction(tree: untpd.Tree, pt: Type)(implicit ctx: Context): Tree = typed(tree, if (defn.isFunctionType(pt)) pt else AnyFunctionProto) - def typedNamed(xtree: untpd.NameTree, pt: Type)(implicit ctx: Context): Tree = { - val tree = xtree withName xtree.name.encode - val sym = xtree.removeAttachment(SymOfTree) match { - case Some(sym) => - sym.ensureCompleted() - sym - case none => - NoSymbol - } - - def localContext = { - val freshCtx = ctx.fresh.setTree(xtree) - if (sym.exists) freshCtx.setOwner(sym) - else freshCtx // can happen for self defs - } + /** Retrieve symbol attached to given tree */ + protected def retrieveSym(tree: untpd.Tree)(implicit ctx: Context) = tree.removeAttachment(SymOfTree) match { + case Some(sym) => + sym.ensureCompleted() + sym + case none => + NoSymbol + } - tree match { - case tree: untpd.Ident => typedIdent(tree, pt) - case tree: untpd.Select => typedSelect(tree, pt) - case tree: untpd.SelectFromTypeTree => typedSelectFromTypeTree(tree, pt) - case tree: untpd.Bind => typedBind(tree, pt) - case tree: untpd.ValDef => - if (tree.isEmpty) tpd.EmptyValDef - else typedValDef(tree, sym)(localContext.setNewScope) - case tree: untpd.DefDef => - val typer1 = nestedTyper.remove(sym).get - typer1.typedDefDef(tree, sym)(localContext.setTyper(typer1)) - case tree: untpd.TypeDef => - if (tree.isClassDef) typedClassDef(tree, sym.asClass)(localContext) - else typedTypeDef(tree, sym)(localContext.setNewScope) - case _ => typedUnadapted(desugar(tree), pt) - } + /** A fresh local context with given tree and owner. + * Owner might not exist (can happen for self valdefs), in which case + * no owner is set in result context + */ + protected def localContext(tree: untpd.Tree, owner: Symbol)(implicit ctx: Context): FreshContext = { + val freshCtx = ctx.fresh.setTree(tree) + if (owner.exists) freshCtx.setOwner(owner) else freshCtx } + protected def localTyper(sym: Symbol): Typer = nestedTyper.remove(sym).get + def typedUnadapted(initTree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = { record("typedUnadapted") val xtree = expanded(initTree) @@ -899,6 +885,26 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case Some(ttree) => ttree case none => + def typedNamed(tree: untpd.NameTree, pt: Type)(implicit ctx: Context): Tree = { + val sym = retrieveSym(xtree) + tree match { + case tree: untpd.Ident => typedIdent(tree, pt) + case tree: untpd.Select => typedSelect(tree, pt) + case tree: untpd.SelectFromTypeTree => typedSelectFromTypeTree(tree, pt) + case tree: untpd.Bind => typedBind(tree, pt) + case tree: untpd.ValDef => + if (tree.isEmpty) tpd.EmptyValDef + else typedValDef(tree, sym)(localContext(tree, sym).setNewScope) + case tree: untpd.DefDef => + val typer1 = localTyper(sym) + typer1.typedDefDef(tree, sym)(localContext(tree, sym).setTyper(typer1)) + case tree: untpd.TypeDef => + if (tree.isClassDef) typedClassDef(tree, sym.asClass)(localContext(tree, sym)) + else typedTypeDef(tree, sym)(localContext(tree, sym).setNewScope) + case _ => typedUnadapted(desugar(tree), pt) + } + } + def typedUnnamed(tree: untpd.Tree): Tree = tree match { case tree: untpd.Apply => if (ctx.mode is Mode.Pattern) typedUnApply(tree, pt) else typedApply(tree, pt) @@ -938,8 +944,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit } xtree match { - case xtree: untpd.NameTree => typedNamed(xtree, pt) - case xtree: untpd.Import => typedImport(xtree, xtree.removeAttachment(SymOfTree).get) + case xtree: untpd.NameTree => typedNamed(xtree withName xtree.name.encode, pt) + case xtree: untpd.Import => typedImport(xtree, retrieveSym(xtree)) case xtree => typedUnnamed(xtree) } }