From 543ff7f4123ded7172fd6ede59f09945efd7c158 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 25 Sep 2014 13:25:06 +0200 Subject: Make changeOwner more robust regarding non-standard owner chains The problem is running changeOwner(from, to) where - from is a ValDef or a Label - an embedded definition has as owner not `from` but some owner of `from`. We allow such denomrlaized owners and the pattern matcher generates them. This patch makes changeOwner take these situations into account. --- src/dotty/tools/dotc/ast/tpd.scala | 15 ++++++++++++-- src/dotty/tools/dotc/core/Flags.scala | 3 +++ src/dotty/tools/dotc/core/SymDenotations.scala | 25 +++++++++++++++--------- src/dotty/tools/dotc/transform/TreeChecker.scala | 15 ++++++++------ test/dotc/tests.scala | 8 ++++---- tests/pos/vararg-pattern.scala | 12 ------------ 6 files changed, 45 insertions(+), 33 deletions(-) delete mode 100644 tests/pos/vararg-pattern.scala diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 101631738..e4450da89 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -525,8 +525,19 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def subst(from: List[Symbol], to: List[Symbol])(implicit ctx: Context): ThisTree = new TreeTypeMap(substFrom = from, substTo = to).apply(tree) - def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree = - new TreeTypeMap(oldOwners = from :: Nil, newOwners = to :: Nil).apply(tree) + /** Change owner from `from` to `to`. If `from` is a weak owner, also change its + * owner to `to`, and continue until a non-weak owner is reached. + */ + def changeOwner(from: Symbol, to: Symbol)(implicit ctx: Context): ThisTree = { + def loop(from: Symbol, froms: List[Symbol], tos: List[Symbol]): ThisTree = { + if (from.isWeakOwner) loop(from.owner, from :: froms, to :: tos) + else { + //println(i"change owner ${from :: froms}%, % ==> $tos of $tree") + new TreeTypeMap(oldOwners = from :: froms, newOwners = tos).apply(tree) + } + } + loop(from, Nil, to :: Nil) + } def select(name: Name)(implicit ctx: Context): Select = Select(tree, name) diff --git a/src/dotty/tools/dotc/core/Flags.scala b/src/dotty/tools/dotc/core/Flags.scala index 896de25fd..e34483f8f 100644 --- a/src/dotty/tools/dotc/core/Flags.scala +++ b/src/dotty/tools/dotc/core/Flags.scala @@ -501,6 +501,9 @@ object Flags { /** Either mutable or lazy */ final val MutableOrLazy = Mutable | Lazy + /** Either method or lazy */ + final val MethodOrLazy = Method | Lazy + /** Labeled `private` or `final` */ final val PrivateOrFinal = Private | Final diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 12a08a112..d0053e679 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -279,8 +279,8 @@ object SymDenotations { do { owner = owner.owner sep += separator - } while (!owner.isClass) - val fn = owner.skipPackageObject.fullNameSeparated(separator) ++ sep ++ name + } while (!owner.isClass && !owner.isPackageObject) + val fn = owner.fullNameSeparated(separator) ++ sep ++ name if (isType) fn.toTypeName else fn.toTermName } @@ -562,6 +562,15 @@ object SymDenotations { result } + /** Symbol is an owner that would be skipped by effectiveOwner. Skipped are + * - package objects + * - labels + * - non-lazy valdefs + */ + def isWeakOwner(implicit ctx: Context): Boolean = + isPackageObject || + isTerm && !is(MethodOrLazy, butNot = Label) && !isLocalDummy + // def isOverridable: Boolean = !!! need to enforce that classes cannot be redefined // def isSkolem: Boolean = ??? @@ -625,14 +634,12 @@ object SymDenotations { } } - /** If this is a package object or its implementing class, its owner, - * otherwise the denoting symbol. - */ - final def skipPackageObject(implicit ctx: Context): Symbol = - if (isPackageObject) owner else symbol + /** If this is a weak owner, its owner, otherwise the denoting symbol. */ + final def skipWeakOwner(implicit ctx: Context): Symbol = + if (isWeakOwner) owner.skipWeakOwner else symbol - /** The owner, skipping package objects. */ - final def effectiveOwner(implicit ctx: Context) = owner.skipPackageObject + /** The owner, skipping package objects, labels and non-lazy valdefs. */ + final def effectiveOwner(implicit ctx: Context) = owner.skipWeakOwner /** The class containing this denotation. * If this denotation is already a class, return itself diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index cf32df61b..ef5baca07 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -97,14 +97,13 @@ class TreeChecker { } private def checkOwner(tree: untpd.Tree)(implicit ctx: Context): Unit = { - def ownerMatches(symOwner: Symbol, ctxOwner: Symbol): Boolean = { + def ownerMatches(symOwner: Symbol, ctxOwner: Symbol): Boolean = symOwner == ctxOwner || - ctxOwner.isTerm && (!(ctxOwner is Method | Lazy | Mutable) || (ctxOwner is Label)) && - ownerMatches(symOwner, ctxOwner.owner) - } + ctxOwner.isWeakOwner && ownerMatches(symOwner, ctxOwner.owner) if(!ownerMatches(tree.symbol.owner, ctx.owner)) { assert(ownerMatches(tree.symbol.owner, ctx.owner), - i"bad owner; ${tree.symbol} has owner ${tree.symbol.owner}, expected was ${ctx.owner}") + i"bad owner; ${tree.symbol} has owner ${tree.symbol.owner}, expected was ${ctx.owner}\n" + + i"owner chain = ${tree.symbol.ownersIterator.toList}%, %, ctxOwners = ${ctx.outersIterator.map(_.owner).toList}%, %") } } @@ -123,7 +122,11 @@ class TreeChecker { * of a helper value without having to do a change owner traversal of the expression. */ override def typedStats(trees: List[untpd.Tree], exprOwner: Symbol)(implicit ctx: Context): List[Tree] = { - for (tree <- trees if tree.isDef) checkOwner(tree) + for (tree <- trees) tree match { + case tree: untpd.DefTree => checkOwner(tree) + case _: untpd.Thicket => assert(false, "unexpanded thicket in statement sequence") + case _ => + } super.typedStats(trees, exprOwner) } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 336c52220..c828712ae 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -109,12 +109,12 @@ class tests extends CompilerTest { // @odersky, fails with datarace @Test def dotc_parsing = compileDir(dotcDir + "tools/dotc/parsing", twice) - // @Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", twice) - // @odersky, elimByName creates symbol with incorrect owner + @Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", twice) + // @odersky, elimByName creates symbol with incorrect owner (fixed) @Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting", twice) - // @Test def dotc_typer = compileDir(dotcDir + "tools/dotc/typer", twice) - // @odersky, elimByName creates symbol with incorrect owner + @Test def dotc_typer = compileDir(dotcDir + "tools/dotc/typer", twice) + // @odersky, elimByName creates symbol with incorrect owner (fixed) @Test def dotc_util = compileDir(dotcDir + "tools/dotc/util", twice) @Test def tools_io = compileDir(dotcDir + "tools/io", twice) diff --git a/tests/pos/vararg-pattern.scala b/tests/pos/vararg-pattern.scala deleted file mode 100644 index 314d6460f..000000000 --- a/tests/pos/vararg-pattern.scala +++ /dev/null @@ -1,12 +0,0 @@ -object Test { - - List(1, 2, 3, 4) match { - case List(1, 2, xs: _*) => - val ys: Seq[Int] = xs - println(ys) - } - val List(1, 2, x: _*) = List(1, 2, 3, 4) - -} - - -- cgit v1.2.3