From 4a78c8959091292e9eda13ef9230acb039cf3824 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 19 Aug 2015 16:05:42 -0700 Subject: Expand names of super accessors Scalac seems to treat superaccessors of traits in a rather peculiar way. They are left unexpanded so that a class implementing several traits with the same superaccessors will get duplicate methods with the same name. It seems this is then resolved in the backend. Here we solve the issue by expanding the names of trait super accessors immediately. --- src/dotty/tools/dotc/transform/ResolveSuper.scala | 4 +++- src/dotty/tools/dotc/transform/SuperAccessors.scala | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/dotty/tools/dotc/transform/ResolveSuper.scala b/src/dotty/tools/dotc/transform/ResolveSuper.scala index 2e1409723..c699476bb 100644 --- a/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -59,7 +59,9 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th private def rebindSuper(base: Symbol, acc: Symbol)(implicit ctx: Context): Symbol = { var bcs = base.info.baseClasses.dropWhile(acc.owner != _).tail var sym: Symbol = NoSymbol - val SuperAccessorName(memberName) = ctx.atPhase(ctx.picklerPhase){ implicit ctx => acc.name }: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type + val originalAccName = + if (acc.is(ExpandedName)) acc.name.unexpandedName else acc.name + val SuperAccessorName(memberName) = originalAccName: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type ctx.debuglog(i"starting rebindsuper from $base of ${acc.showLocated}: ${acc.info} in $bcs, name = $memberName") while (bcs.nonEmpty && sym == NoSymbol) { val other = bcs.head.info.nonPrivateDecl(memberName) diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index 23201a978..de01cc27e 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -71,11 +71,12 @@ class SuperAccessors(thisTransformer: DenotTransformer) { val Select(qual, name) = sel val sym = sel.symbol val clazz = qual.symbol.asClass - val supername = name.superName + var supername = name.superName + if (clazz is Trait) supername = supername.expandedName(clazz) val superAcc = clazz.info.decl(supername).suchThat(_.signature == sym.signature).symbol orElse { ctx.debuglog(s"add super acc ${sym.showLocated} to $clazz") - val deferredOrPrivate = if (clazz is Trait) Deferred else Private + val deferredOrPrivate = if (clazz is Trait) Deferred | ExpandedName else Private val acc = ctx.newSymbol( clazz, supername, SuperAccessor | Artifact | Method | deferredOrPrivate, sel.tpe.widenSingleton.ensureMethodic, coord = sym.coord).enteredAfter(thisTransformer) @@ -110,6 +111,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { ctx.error( i"${sym.showLocated} is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override'", sel.pos) + else println(i"ok super $sel ${sym.showLocated} $member $clazz ${member.isIncompleteIn(clazz)}") } else if (mix == tpnme.EMPTY && !(sym.owner is Trait)) // SI-4989 Check if an intermediate class between `clazz` and `sym.owner` redeclares the method as abstract. -- cgit v1.2.3 From cc5dce545e1150021bcd3d312574bdf3b657512c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 19 Aug 2015 16:06:35 -0700 Subject: Fix test when abstract override is needed. There was a transcription error from scalac which caused the scope of a `!` to be wrong. --- src/dotty/tools/dotc/transform/SuperAccessors.scala | 2 +- test/dotc/tests.scala | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index de01cc27e..31cfef914 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -107,7 +107,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { val member = sym.overridingSymbol(clazz) if (mix != tpnme.EMPTY || !member.exists || - !(member is AbsOverride) && member.isIncompleteIn(clazz)) + !((member is AbsOverride) && member.isIncompleteIn(clazz))) ctx.error( i"${sym.showLocated} is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override'", sel.pos) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index b39d0e928..26ae099d3 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -96,6 +96,7 @@ class tests extends CompilerTest { @Test def new_all = compileFiles(newDir, twice) + @Test def neg_abstractOverride() = compileFile(negDir, "abstract-override", xerrors = 2) @Test def neg_blockescapes() = compileFile(negDir, "blockescapesNeg", xerrors = 1) @Test def neg_typedapply() = compileFile(negDir, "typedapply", xerrors = 4) @Test def neg_typedidents() = compileFile(negDir, "typedIdents", xerrors = 2) -- cgit v1.2.3 From aaae0df80376668d1c502857695b43d42083c888 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 Aug 2015 15:08:47 +0200 Subject: Workaround for #765 Avoid using unexpanded name because it can give wrong results for super accessors of symbolic names. See #765. Without this commit t2183.scala crashes the compiler. --- src/dotty/tools/dotc/core/NameOps.scala | 5 +++++ src/dotty/tools/dotc/transform/ResolveSuper.scala | 10 +++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index 593d5f036..cab47025e 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -167,6 +167,11 @@ object NameOps { def expandedName(prefix: Name): N = expandedName(prefix, nme.EXPAND_SEPARATOR) + /** Revert the expanded name. Note: This currently gives incorrect results + * if the normal name contains `nme.EXPAND_SEPARATOR`, i.e. two consecutive '$' + * signs. This can happen for instance if a super accessor is paired with + * an encoded name, e.g. super$$plus$eq. See #765. + */ def unexpandedName: N = { val idx = name.lastIndexOfSlice(nme.EXPAND_SEPARATOR) if (idx < 0) name else (name drop (idx + nme.EXPAND_SEPARATOR.length)).asInstanceOf[N] diff --git a/src/dotty/tools/dotc/transform/ResolveSuper.scala b/src/dotty/tools/dotc/transform/ResolveSuper.scala index c699476bb..26128cf33 100644 --- a/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -59,9 +59,13 @@ class ResolveSuper extends MiniPhaseTransform with IdentityDenotTransformer { th private def rebindSuper(base: Symbol, acc: Symbol)(implicit ctx: Context): Symbol = { var bcs = base.info.baseClasses.dropWhile(acc.owner != _).tail var sym: Symbol = NoSymbol - val originalAccName = - if (acc.is(ExpandedName)) acc.name.unexpandedName else acc.name - val SuperAccessorName(memberName) = originalAccName: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type + val unexpandedAccName = + if (acc.is(ExpandedName)) // Cannot use unexpandedName because of #765. t2183.scala would fail if we did. + acc.name + .drop(acc.name.indexOfSlice(nme.EXPAND_SEPARATOR ++ nme.SUPER_PREFIX)) + .drop(nme.EXPAND_SEPARATOR.length) + else acc.name + val SuperAccessorName(memberName) = unexpandedAccName: Name // dotty deviation: ": Name" needed otherwise pattern type is neither a subtype nor a supertype of selector type ctx.debuglog(i"starting rebindsuper from $base of ${acc.showLocated}: ${acc.info} in $bcs, name = $memberName") while (bcs.nonEmpty && sym == NoSymbol) { val other = bcs.head.info.nonPrivateDecl(memberName) -- cgit v1.2.3 From 2b162ffff6a1a969781c0a5790a679bc22da64d9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 Aug 2015 15:12:01 +0200 Subject: Add test case --- tests/run/i756.scala | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/run/i756.scala diff --git a/tests/run/i756.scala b/tests/run/i756.scala new file mode 100644 index 000000000..dd9b2be4f --- /dev/null +++ b/tests/run/i756.scala @@ -0,0 +1,8 @@ +trait T { def foo: Int = 3 } +trait T1 extends T { override def foo = super.foo } +trait T2 extends T { override def foo = super.foo } +object Test extends T2 with T1 { + def main(args: Array[String]) = { + assert(foo == 3) + } +} -- cgit v1.2.3 From 4689bd39e3c5271333bb6dec1370b4e5c802f7e0 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 21 Aug 2015 20:27:15 +0200 Subject: Add missing negative test. --- tests/neg/abstract-override.scala | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/neg/abstract-override.scala diff --git a/tests/neg/abstract-override.scala b/tests/neg/abstract-override.scala new file mode 100644 index 000000000..c1ce83725 --- /dev/null +++ b/tests/neg/abstract-override.scala @@ -0,0 +1,8 @@ +trait T { def foo: Int } +trait T1 extends T { override def foo = super.foo } +trait T2 extends T { override def foo = super.foo } +object Test extends T2 with T1 { + def main(args: Array[String]) = { + assert(foo == 3) + } +} -- cgit v1.2.3