From 90d7b5e10d8e3270759f686e6fe8352623355266 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 1 Dec 2020 21:52:32 +0100 Subject: [PATCH 1/2] Fix #10285: Fix combinations of trait setter names and other derived names Adding "_=" to the last part of a name does not work if that name is a unique name or other derived name, since the resulting name would print like `x_=$1` instead of `x$1_=`. Use a new semantic name for synthetic setter suffix instead. --- .../src/dotty/tools/dotc/core/NameKinds.scala | 1 + .../src/dotty/tools/dotc/core/NameOps.scala | 21 ++++++++++------ .../src/dotty/tools/dotc/core/NameTags.scala | 2 ++ .../dotty/tools/dotc/transform/Mixin.scala | 2 +- tests/run/i10285.scala | 25 +++++++++++++++++++ 5 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 tests/run/i10285.scala diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index aa11660710b5..24ffecbef359 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -367,6 +367,7 @@ object NameKinds { val ModuleClassName: SuffixNameKind = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") val ImplMethName: SuffixNameKind = new SuffixNameKind(IMPLMETH, "$") val AdaptedClosureName: SuffixNameKind = new SuffixNameKind(ADAPTEDCLOSURE, "$adapted") { override def definesNewName = true } + val SyntheticSetterName: SuffixNameKind = new SuffixNameKind(SETTER, "_=") /** A name together with a signature. Used in Tasty trees. */ object SignedName extends NameKind(SIGNED) { diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 6cfdedbe9a27..b9d45385f389 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -1,4 +1,5 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package core import java.security.MessageDigest @@ -9,7 +10,7 @@ import Names._, StdNames._, Contexts._, Symbols._, Flags._, NameKinds._, Types._ import util.Chars.{isOperatorPart, digit2int} import Definitions._ import nme._ -import Decorators.concat +import Decorators._ object NameOps { @@ -69,7 +70,7 @@ object NameOps { def isLocalDummyName: Boolean = name startsWith str.LOCALDUMMY_PREFIX def isReplWrapperName: Boolean = name.toString contains str.REPL_SESSION_LINE def isReplAssignName: Boolean = name.toString contains str.REPL_ASSIGN_SUFFIX - def isSetterName: Boolean = name endsWith str.SETTER_SUFFIX + def isSetterName: Boolean = name.endsWith(str.SETTER_SUFFIX) || name.is(SyntheticSetterName) def isScala2LocalSuffix: Boolean = testSimple(_.endsWith(" ")) def isSelectorName: Boolean = testSimple(n => n.startsWith("_") && n.drop(1).forall(_.isDigit)) def isAnonymousClassName: Boolean = name.startsWith(str.ANON_CLASS) @@ -347,17 +348,21 @@ object NameOps { def setterName: TermName = name.exclude(FieldName) ++ str.SETTER_SUFFIX + def syntheticSetterName = SyntheticSetterName(name.exclude(FieldName)) + def getterName: TermName = - name.exclude(FieldName).mapLast(n => + val name1 = name.exclude(FieldName) + if name1.is(SyntheticSetterName) then name1.exclude(SyntheticSetterName) + else name1.mapLast(n => if (n.endsWith(str.SETTER_SUFFIX)) n.take(n.length - str.SETTER_SUFFIX.length).asSimpleName else n) def fieldName: TermName = if (name.isSetterName) - if (name.is(TraitSetterName)) { - val TraitSetterName(_, original) = name - original.fieldName - } + if name.is(SyntheticSetterName) then + name.exclude(SyntheticSetterName) + .replace { case TraitSetterName(_, original) => original } + .fieldName else getterName.fieldName else FieldName(name.toSimpleName) diff --git a/compiler/src/dotty/tools/dotc/core/NameTags.scala b/compiler/src/dotty/tools/dotc/core/NameTags.scala index c570f300a4bf..63aea8853235 100644 --- a/compiler/src/dotty/tools/dotc/core/NameTags.scala +++ b/compiler/src/dotty/tools/dotc/core/NameTags.scala @@ -29,6 +29,8 @@ object NameTags extends TastyFormat.NameTags { final val PARAMACC = 33 // Used for a private parameter alias + final val SETTER = 34 // A synthesized += suffix. + def nameTagToString(tag: Int): String = tag match { case UTF8 => "UTF8" case QUALIFIED => "QUALIFIED" diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index 7b8e2b986e3a..20f40fd96515 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -25,7 +25,7 @@ object Mixin { def traitSetterName(getter: TermSymbol)(using Context): TermName = getter.ensureNotPrivate.name .expandedName(getter.owner, TraitSetterName) - .asTermName.setterName + .asTermName.syntheticSetterName } /** This phase performs the following transformations: diff --git a/tests/run/i10285.scala b/tests/run/i10285.scala new file mode 100644 index 000000000000..5019bae43ca7 --- /dev/null +++ b/tests/run/i10285.scala @@ -0,0 +1,25 @@ +trait Companion { + + trait AbstractFoo { + val a0 = 1 + private val b0 = 2 + def b1 = b0 + val (a, b) = { + val av = 1 + val bv = 2 + (av, bv) + } + } +} + +object Bar extends Companion { + class FooImpl extends AbstractFoo + val foo = new FooImpl() +} + +object Test { + val foo = new Bar.FooImpl + def main(args: Array[String]): Unit = + assert(Bar.foo.a0 + Bar.foo.b1 == 3) + assert(Bar.foo.a + Bar.foo.b == 3) +} \ No newline at end of file From edc0a23d4f1e2b1eb9b4d26af1123b955b196f1e Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 1 Dec 2020 22:25:53 +0100 Subject: [PATCH 2/2] Use mangled suffix for synthetic setters --- compiler/src/dotty/tools/dotc/core/NameKinds.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameKinds.scala b/compiler/src/dotty/tools/dotc/core/NameKinds.scala index 24ffecbef359..e17e772de993 100644 --- a/compiler/src/dotty/tools/dotc/core/NameKinds.scala +++ b/compiler/src/dotty/tools/dotc/core/NameKinds.scala @@ -367,7 +367,7 @@ object NameKinds { val ModuleClassName: SuffixNameKind = new SuffixNameKind(OBJECTCLASS, "$", optInfoString = "ModuleClass") val ImplMethName: SuffixNameKind = new SuffixNameKind(IMPLMETH, "$") val AdaptedClosureName: SuffixNameKind = new SuffixNameKind(ADAPTEDCLOSURE, "$adapted") { override def definesNewName = true } - val SyntheticSetterName: SuffixNameKind = new SuffixNameKind(SETTER, "_=") + val SyntheticSetterName: SuffixNameKind = new SuffixNameKind(SETTER, "_$eq") /** A name together with a signature. Used in Tasty trees. */ object SignedName extends NameKind(SIGNED) {