diff --git a/compiler/src/dotty/tools/dotc/transform/Mixin.scala b/compiler/src/dotty/tools/dotc/transform/Mixin.scala index fc335b66a25c..d223566a208c 100644 --- a/compiler/src/dotty/tools/dotc/transform/Mixin.scala +++ b/compiler/src/dotty/tools/dotc/transform/Mixin.scala @@ -258,7 +258,7 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => && !wasOneOf(getter, Deferred) && !getter.isConstExprFinalVal yield - if (isCurrent(getter) || getter.name.is(ExpandedName)) { + if (isInImplementingClass(getter) || getter.name.is(ExpandedName)) { val rhs = if (wasOneOf(getter, ParamAccessor)) nextArgument() @@ -271,6 +271,9 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase => // transformFollowing call is needed to make memoize & lazy vals run transformFollowing(DefDef(mkForwarderSym(getter.asTerm), rhs)) } + else if wasOneOf(getter, ParamAccessor) then + // mixin parameter field is defined by an override; evaluate the argument and throw it away + nextArgument() else EmptyTree } diff --git a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala index ff73705645a4..1b25061a4020 100644 --- a/compiler/src/dotty/tools/dotc/transform/MixinOps.scala +++ b/compiler/src/dotty/tools/dotc/transform/MixinOps.scala @@ -42,7 +42,7 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(using Context) { /** Is `sym` a member of implementing class `cls`? * The test is performed at phase `thisPhase`. */ - def isCurrent(sym: Symbol): Boolean = + def isInImplementingClass(sym: Symbol): Boolean = atPhase(thisPhase) { cls.info.nonPrivateMember(sym.name).hasAltWith(_.symbol == sym) } @@ -71,7 +71,7 @@ class MixinOps(cls: ClassSymbol, thisPhase: DenotTransformer)(using Context) { meth.is(Method, butNot = PrivateOrAccessorOrDeferred) && (ctx.settings.mixinForwarderChoices.isTruthy || meth.owner.is(Scala2x) || needsDisambiguation || hasNonInterfaceDefinition || generateJUnitForwarder || generateSerializationForwarder) && - isCurrent(meth) + isInImplementingClass(meth) } final val PrivateOrAccessor: FlagSet = Private | Accessor diff --git a/docs/docs/reference/other-new-features/trait-parameters.md b/docs/docs/reference/other-new-features/trait-parameters.md index f930c10e2c5d..1655e338b32c 100644 --- a/docs/docs/reference/other-new-features/trait-parameters.md +++ b/docs/docs/reference/other-new-features/trait-parameters.md @@ -26,14 +26,12 @@ class D extends C, Greeting("Bill") // error: parameter passed twice Should this print "Bob" or "Bill"? In fact this program is illegal, because it violates the second rule of the following for trait parameters: - 1. If a class `C` directly extends a parameterized trait `T`, and its superclass does not, `C` _must_ pass arguments to `T`. + 1. If a class `C` extends a parameterized trait `T`, and its superclass does not, `C` _must_ pass arguments to `T`. - 2. If a class `C` directly or indirectly extends a parameterized trait `T`, and its superclass does as well, `C` _must not_ pass arguments to `T`. + 2. If a class `C` extends a parameterized trait `T`, and its superclass does as well, `C` _must not_ pass arguments to `T`. 3. Traits must never pass arguments to parent traits. - 4. If a class `C` extends a parameterized trait `T` only indirectly, and its superclass does not extend `T`, then all parameters of `T` must be defined via overrides. - Here's a trait extending the parameterized trait `Greeting`. ```scala @@ -53,13 +51,6 @@ The correct way to write `E` is to extend both `Greeting` and ```scala class E extends Greeting("Bob"), FormalGreeting ``` -Alternatively, a class could also define the `name` parameter of `Greeting` using -an override, using rule (4) above: - -```scala -class E2 extends FormalGreeting: - override val name: String = "Bob" -``` ## Reference diff --git a/tests/pos/i11214.scala b/tests/neg/i11214.scala similarity index 60% rename from tests/pos/i11214.scala rename to tests/neg/i11214.scala index 154f203b7e20..ae4184927f3a 100644 --- a/tests/pos/i11214.scala +++ b/tests/neg/i11214.scala @@ -1,5 +1,5 @@ trait Pet(val name: String) trait FeatheredPet extends Pet -class Bird(override val name: String) extends FeatheredPet: +class Bird(override val name: String) extends FeatheredPet: // error override def toString = s"bird name: $name" \ No newline at end of file diff --git a/tests/run/i11344.scala b/tests/run/i11344.scala new file mode 100644 index 000000000000..4e87f04e1de3 --- /dev/null +++ b/tests/run/i11344.scala @@ -0,0 +1,8 @@ +trait Pet(val name: String, rest: Int): + def f(suffix: String) = s"$name$suffix$rest" + +class Birdie(override val name: String) extends Pet("huh", 1) + +@main def Test = + assert(Birdie("Polly").f("more") == "Pollymore1") +