From dd53b26706254985ba6b4faa9c89272571857906 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 27 Mar 2014 15:02:02 +0100 Subject: 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 b3bf2f134..17d4d6712 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 f07eaa2be..e96f08855 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}") -- cgit v1.2.3 From c62d021cdcc0a3dda6daffd74daf8eaf48aeae88 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Mar 2014 12:57:54 +0100 Subject: 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 a7a33ce8e..8799f9fd0 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 } -- cgit v1.2.3 From ad437d8fa9bd4127889569952ae6fdb048d2b1ec Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Mar 2014 13:00:28 +0100 Subject: 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 173f81894..3f29fc72f 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 3ae74b467..311abd8e1 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 1c453750e..48a377c02 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 -- cgit v1.2.3 From e5d51859bd3d6fd0b286aa6c8e710f33f95b97cd Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Mar 2014 13:11:17 +0100 Subject: 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 709f4b2db..6fd69beb8 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 000000000..ff25a94de --- /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 -- cgit v1.2.3 From a73b510b82460247524a07a6dd4f0bfaac74ccfc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 28 Mar 2014 13:07:22 +0100 Subject: 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 9cd635cd9..4b251f183 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 8be73ac82..3060f3951 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) -- cgit v1.2.3 From 26b8ec48adec709cf2b07b470ada774c708e96a4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 29 Mar 2014 15:02:51 +0100 Subject: 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 cd9680e64..21f914d99 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 87242c9b5..8b5606da2 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 10857da5a..684714199 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 -- cgit v1.2.3 From fc4648d33a051ff5d220c2fea097fc99b5883ecc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 29 Mar 2014 15:05:07 +0100 Subject: 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 ++++---- src/dotty/tools/dotc/config/ScalaSettings.scala | 2 +- src/dotty/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 3f15bd4c3..264373baf 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 8ed725e36..144e146c1 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 000000000..ea3afc679 --- /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 -- cgit v1.2.3 From 9bd1e6a99e1cb09a3527e548699d1561e72e36d3 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 10:49:42 +0200 Subject: 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 +- src/dotty/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 311abd8e1..46878d3ca 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 d59bdf1a9..842e2f81f 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 f9b602f54..b403d4e66 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 3060f3951..5345b7396 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 ed6f3b5d9..dcd5c67c8 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 000000000..779d1847e --- /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) + +} -- cgit v1.2.3 From 5c1a1498c7215935d466379d7fa85f88f4a001c7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 14:41:09 +0200 Subject: 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 + .../dotc/transform/PostTyperTransformers.scala | 4 +- src/dotty/tools/dotc/transform/Splitter.scala | 27 ++++ src/dotty/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 6fd69beb8..1e8f13578 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 8d083b29c..8721bc548 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 14e2cf35d..25f122cf5 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 000000000..9c01574aa --- /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 684714199..425410ae7 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]] } } -- cgit v1.2.3 From cac8c752b626bc0a5f872572f8ec07274f5e9e0e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 10:28:23 +0200 Subject: 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 48a377c02..54f72c20c 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) { -- cgit v1.2.3 From d173cc048ebdbff30f6537f207118fc5717b8787 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 14:45:51 +0200 Subject: 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 8721bc548..4ccc9be73 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 8990d21a2..db549b2d4 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 9c4ce232e..173ac3aeb 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 e81949f05..d0e78185f 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 87bc643a3..b72cd0fa8 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) -- cgit v1.2.3 From 318db7dc616a659687d95380efa16159cfaeb984 Mon Sep 17 00:00:00 2001 From: Dmitry Petrashko Date: Mon, 31 Mar 2014 14:53:44 +0200 Subject: 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 4ccc9be73..b0214a631 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) -- cgit v1.2.3 From fb9a9e65c941a7b840baaa32641818d32b45b5b7 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 30 Mar 2014 16:31:01 +0200 Subject: 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 b403d4e66..d4156e1d7 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 000000000..896dbba7d --- /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 b72cd0fa8..c2488f68c 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) } } -- cgit v1.2.3