From b5f307d41632d5338d24bec95685b6304bcaea10 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 25 Sep 2022 11:58:12 +0200 Subject: [PATCH 1/8] Disallow overriding val parameters We disallow overriding of val parameters, which fixes the soundness problem discovered in #16092. There is one exception: If a val parameter is overridden by another val parameter that can be shown to always have the same value (in the sense established by Paramforwarding.inheritedAccessor). This exception is needed to make a not-so-uncommon pattern of case class inheritance go through. Example: abstract class A(val x: Int) case class B(override val x: Int) extends A(x) case class C(override val x: Int) extends A(x) case object D extends A(0) Here, the `override val`s are necessary since case class parameters are always vals, so they do override the val in class A. It should be noted that the override val generates a second field, so this not a very efficient representation. A better design would be to use an abstract field in `A`: abstract class A { val x: Int } case class B(val x: Int) extends A case class C(val x: Int) extends A case object D extends A { val a = 0 } But that causes slightly more work for cases as in D. Which seems to be why the first pattern is sometimes used. It might be desirable to disallow the second pattern, but that would cause quite a bit of migration hassle since it requires synchronized changes at several places of a class hierarchy. --- .../dotc/transform/ParamForwarding.scala | 31 ++++++++++--------- .../dotty/tools/dotc/typer/RefChecks.scala | 6 ++++ tests/init/neg/override5.scala | 6 ---- tests/neg/i11344.scala | 6 ++++ tests/neg/i16092-members-only.scala | 31 +++++++++++++++++++ tests/neg/i16092.scala | 24 ++++++++++++++ tests/neg/i9460.scala | 4 +-- .../tasty/test-definitions.scala | 15 ++++++--- tests/pos/i16092.scala | 5 +++ tests/pos/i2051.scala | 3 -- tests/run/i11344.scala | 8 ----- tests/run/i16092.scala | 8 +++++ tests/run/paramForwarding.scala | 3 +- 13 files changed, 109 insertions(+), 41 deletions(-) create mode 100644 tests/neg/i11344.scala create mode 100644 tests/neg/i16092-members-only.scala create mode 100644 tests/neg/i16092.scala create mode 100644 tests/pos/i16092.scala delete mode 100644 tests/run/i11344.scala create mode 100644 tests/run/i16092.scala diff --git a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala index 94ea48e14efd..8c93ffb90232 100644 --- a/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala +++ b/compiler/src/dotty/tools/dotc/transform/ParamForwarding.scala @@ -30,7 +30,8 @@ import NameKinds.ParamAccessorName * The aim of this transformation is to avoid redundant parameter accessor fields. */ class ParamForwarding extends MiniPhase with IdentityDenotTransformer: - import ast.tpd._ + import ast.tpd.* + import ParamForwarding.inheritedAccessor private def thisPhase: ParamForwarding = this @@ -39,20 +40,6 @@ class ParamForwarding extends MiniPhase with IdentityDenotTransformer: override def description: String = ParamForwarding.description def transformIfParamAlias(mdef: ValOrDefDef)(using Context): Tree = - - def inheritedAccessor(sym: Symbol)(using Context): Symbol = - val candidate = sym.owner.asClass.superClass - .info.decl(sym.name).suchThat(_.is(ParamAccessor, butNot = Mutable)) - .symbol - if !candidate.is(Private) // candidate might be private and accessible if it is in an outer class - && candidate.isAccessibleFrom(currentClass.thisType, superAccess = true) - then - candidate - else if candidate.is(SuperParamAlias) then - inheritedAccessor(candidate) - else - NoSymbol - val sym = mdef.symbol.asTerm if sym.is(SuperParamAlias) then assert(sym.is(ParamAccessor, butNot = Mutable)) @@ -84,3 +71,17 @@ class ParamForwarding extends MiniPhase with IdentityDenotTransformer: object ParamForwarding: val name: String = "paramForwarding" val description: String = "add forwarders for aliases of superclass parameters" + + def inheritedAccessor(sym: Symbol)(using Context): Symbol = + val candidate = sym.owner.asClass.superClass + .info.decl(sym.name).suchThat(_.is(ParamAccessor, butNot = Mutable)) + .symbol + if !candidate.is(Private) // candidate might be private and accessible if it is in an outer class + && candidate.isAccessibleFrom(currentClass.thisType, superAccess = true) + then + candidate + else if candidate.is(SuperParamAlias) then + inheritedAccessor(candidate) + else + NoSymbol +end ParamForwarding \ No newline at end of file diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 94eacca5c7db..9608f360b513 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -264,6 +264,8 @@ object RefChecks { * 1.10. If O is inline (and deferred, otherwise O would be final), M must be inline * 1.11. If O is a Scala-2 macro, M must be a Scala-2 macro. * 1.12. If O is non-experimental, M must be non-experimental. + * 1.13 If O is a val parameter, M must be a val parameter that passes on its + * value to O. * 2. Check that only abstract classes have deferred members * 3. Check that concrete classes do not have deferred definitions * that are not implemented in a subclass. @@ -446,6 +448,10 @@ object RefChecks { overrideError("cannot be used here - classes can only override abstract types") else if other.isEffectivelyFinal then // (1.2) overrideError(i"cannot override final member ${other.showLocated}") + else if other.is(ParamAccessor) && + !(member.is(ParamAccessor) && ParamForwarding.inheritedAccessor(member) == other) + then // (1.13) + overrideError(i"cannot override val parameter ${other.showLocated}") else if (member.is(ExtensionMethod) && !other.is(ExtensionMethod)) // (1.3) overrideError("is an extension method, cannot override a normal method") else if (other.is(ExtensionMethod) && !member.is(ExtensionMethod)) // (1.3) diff --git a/tests/init/neg/override5.scala b/tests/init/neg/override5.scala index 8160793c5e35..061a41dc3fc2 100644 --- a/tests/init/neg/override5.scala +++ b/tests/init/neg/override5.scala @@ -25,9 +25,3 @@ trait Base { val message = "hello, " + name } - -class Derived(val name: String) extends Base - -class Derived2 extends Derived("hello") { - override val name: String = "ok" // error -} diff --git a/tests/neg/i11344.scala b/tests/neg/i11344.scala new file mode 100644 index 000000000000..4829b9fcef6b --- /dev/null +++ b/tests/neg/i11344.scala @@ -0,0 +1,6 @@ +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) // error + + diff --git a/tests/neg/i16092-members-only.scala b/tests/neg/i16092-members-only.scala new file mode 100644 index 000000000000..d0161931628a --- /dev/null +++ b/tests/neg/i16092-members-only.scala @@ -0,0 +1,31 @@ +trait X: + type T + def process(t: T): Unit + +abstract class Z: + def x1: X + val x: X = x1 + def t: x.T + def process(): Unit = x.process(t) + +class Evil extends Z: + def x2: X + override val x: X = x2 + +// alarm bells should be ringing by now + +// taking it to its conclusion... +object X1 extends X: + override type T = Int + override def process(t: T): Unit = println("Int: " + t) + +object X2 extends X: + override type T = String + override def process(t: T): Unit = println("String: " + t) + +@main def Test = + new Evil{ + val x1 = X1 + val x2 = X2 + val t = 42 // error + }.process() // BOOM: basically did x2.process(42) diff --git a/tests/neg/i16092.scala b/tests/neg/i16092.scala new file mode 100644 index 000000000000..c24e030087a2 --- /dev/null +++ b/tests/neg/i16092.scala @@ -0,0 +1,24 @@ +trait X { + type T + def process(t: T): Unit +} + +class Z(val x: X, val t: x.T) { + def process(): Unit = x.process(t) +} +class Evil(x1: X, x2: X, t: x1.T) extends Z(x1, t) { + val x: X = x2 // error breaks connection between x and t +} +// alarm bells should be ringing by now + +// taking it to its conclusion... +object x1 extends X { + override type T = Int + override def process(t: T): Unit = println("Int: " + t) +} +object x2 extends X { + override type T = String + override def process(t: T): Unit = println("String: " + t) +} + +@main def Test = new Evil(x1, x2, 42).process() // BOOM: basically did x2.process(42) diff --git a/tests/neg/i9460.scala b/tests/neg/i9460.scala index 9cc08bf2ad4d..2290b07a9759 100644 --- a/tests/neg/i9460.scala +++ b/tests/neg/i9460.scala @@ -1,4 +1,4 @@ -trait A(val s: String) { println(s) } -trait B extends A { override val s = "B" } // requires override val s +trait A(s: String) { println(s) } +trait B extends A { val s = "B" } class C extends B // error @main def Test = C() diff --git a/tests/pos-with-compiler/tasty/test-definitions.scala b/tests/pos-with-compiler/tasty/test-definitions.scala index 3def4d22d62a..7bbeeda2083a 100644 --- a/tests/pos-with-compiler/tasty/test-definitions.scala +++ b/tests/pos-with-compiler/tasty/test-definitions.scala @@ -163,9 +163,9 @@ object definitions { } } - abstract class LambdaType[ParamInfo, This <: LambdaType[ParamInfo, This]]( + abstract class LambdaType[ParamInfo, This <: LambdaType[ParamInfo, This]] + extends Type { val companion: LambdaTypeCompanion[ParamInfo, This] - ) extends Type { private[Type] var _pinfos: List[ParamInfo] private[Type] var _restpe: Type @@ -186,16 +186,21 @@ object definitions { } case class MethodType(paramNames: List[String], private[Type] var _pinfos: List[Type], private[Type] var _restpe: Type) - extends LambdaType[Type, MethodType](MethodType) { + extends LambdaType[Type, MethodType] { + override val companion = MethodType def isImplicit = (companion `eq` ImplicitMethodType) || (companion `eq` ErasedImplicitMethodType) def isErased = (companion `eq` ErasedMethodType) || (companion `eq` ErasedImplicitMethodType) } case class PolyType(paramNames: List[String], private[Type] var _pinfos: List[TypeBounds], private[Type] var _restpe: Type) - extends LambdaType[TypeBounds, PolyType](PolyType) + extends LambdaType[TypeBounds, PolyType] { + override val companion = PolyType + } case class TypeLambda(paramNames: List[String], private[Type] var _pinfos: List[TypeBounds], private[Type] var _restpe: Type) - extends LambdaType[TypeBounds, TypeLambda](TypeLambda) + extends LambdaType[TypeBounds, TypeLambda] { + override val companion = TypeLambda + } object TypeLambda extends LambdaTypeCompanion[TypeBounds, TypeLambda] object PolyType extends LambdaTypeCompanion[TypeBounds, PolyType] diff --git a/tests/pos/i16092.scala b/tests/pos/i16092.scala new file mode 100644 index 000000000000..4d0f3e539ca7 --- /dev/null +++ b/tests/pos/i16092.scala @@ -0,0 +1,5 @@ +class A(val x: Int) +class B(override val x: Int) extends A(x) + +class C(x: Int) extends A(x) +case class D(override val x: Int) extends C(x) diff --git a/tests/pos/i2051.scala b/tests/pos/i2051.scala index 9e29eea22a2f..b8c59a0ddb58 100644 --- a/tests/pos/i2051.scala +++ b/tests/pos/i2051.scala @@ -4,6 +4,3 @@ class B[T](override val x:T) extends A[T](x) class C[T](val x:T, val y: Int, val z: Boolean) class D[T](override val x:T, y: Int, z: Boolean) extends C[T](x, y, z) -trait X(val x: Int, y: Int, z: Int) -trait Y(override val x: Int, y: Int, z: Int) extends X -class Z(override val x: Int, y: Int, z: Int) extends Y(x, y, z) with X(x, y, z) diff --git a/tests/run/i11344.scala b/tests/run/i11344.scala deleted file mode 100644 index 4e87f04e1de3..000000000000 --- a/tests/run/i11344.scala +++ /dev/null @@ -1,8 +0,0 @@ -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") - diff --git a/tests/run/i16092.scala b/tests/run/i16092.scala new file mode 100644 index 000000000000..1e630e305088 --- /dev/null +++ b/tests/run/i16092.scala @@ -0,0 +1,8 @@ + +class A(a: Int) + +class B extends A(1): + val a = 2 // ok + +@main def Test = + assert(B().a == 2) diff --git a/tests/run/paramForwarding.scala b/tests/run/paramForwarding.scala index d999d193288d..5c0b69fd2072 100644 --- a/tests/run/paramForwarding.scala +++ b/tests/run/paramForwarding.scala @@ -16,8 +16,7 @@ class B(override val theValue: Int) extends A(42) { // Bz contains a field Bz.theValue$$local accessible using the getter // Bz.theValue() which overrides A.theValue() -class Bz extends A(42) { - override val theValue: Int = 10 +class Bz(override val theValue: Int = 10) extends A(42) { val theValueInBz = theValue } From 34d87db62ac7d775cfb8d3e66b2d6e8fc81fed66 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 25 Sep 2022 12:24:37 +0200 Subject: [PATCH 2/8] Reject overrides only with -source future Currently, the following CB projects have illegal overrides of val parameters - spire - scalaz - specs2 - akka I checked the spire issue and its seems to require a non-trivial refactoring to avoid the problem. More than I could achieve, given that I know nothing of spire. In light of this I think we can enforce the restriction only under -source future and make it a deprecation warning for now. --- .../dotty/tools/dotc/typer/RefChecks.scala | 21 ++++++++++++------- .../deprecation}/i11344.scala | 0 tests/{neg => neg-strict}/i16092.scala | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) rename tests/{neg => neg-custom-args/deprecation}/i11344.scala (100%) rename tests/{neg => neg-strict}/i16092.scala (89%) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 9608f360b513..9cf7347645c1 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -15,8 +15,8 @@ import config.Printers.{checks, noPrinter} import Decorators._ import OverridingPairs.isOverridingPair import typer.ErrorReporting._ -import config.Feature.{warnOnMigration, migrateTo3} -import config.SourceVersion.`3.0` +import config.Feature.{warnOnMigration, migrateTo3, sourceVersion} +import config.SourceVersion.{`3.0`, `future`} import config.Printers.refcheck import reporting._ import Constants.Constant @@ -264,8 +264,8 @@ object RefChecks { * 1.10. If O is inline (and deferred, otherwise O would be final), M must be inline * 1.11. If O is a Scala-2 macro, M must be a Scala-2 macro. * 1.12. If O is non-experimental, M must be non-experimental. - * 1.13 If O is a val parameter, M must be a val parameter that passes on its - * value to O. + * 1.13 Under -source future, if O is a val parameter, M must be a val parameter + * that passes its on to O. * 2. Check that only abstract classes have deferred members * 3. Check that concrete classes do not have deferred definitions * that are not implemented in a subclass. @@ -448,10 +448,6 @@ object RefChecks { overrideError("cannot be used here - classes can only override abstract types") else if other.isEffectivelyFinal then // (1.2) overrideError(i"cannot override final member ${other.showLocated}") - else if other.is(ParamAccessor) && - !(member.is(ParamAccessor) && ParamForwarding.inheritedAccessor(member) == other) - then // (1.13) - overrideError(i"cannot override val parameter ${other.showLocated}") else if (member.is(ExtensionMethod) && !other.is(ExtensionMethod)) // (1.3) overrideError("is an extension method, cannot override a normal method") else if (other.is(ExtensionMethod) && !member.is(ExtensionMethod)) // (1.3) @@ -520,6 +516,15 @@ object RefChecks { overrideError(i"needs to be declared with @targetName(${"\""}${other.targetName}${"\""}) so that external names match") else overrideError("cannot have a @targetName annotation since external names would be different") + else if other.is(ParamAccessor) + && !(member.is(ParamAccessor) && ParamForwarding.inheritedAccessor(member) == other) + then // (1.13) + if sourceVersion.isAtLeast(`future`) then + overrideError(i"cannot override val parameter ${other.showLocated}") + else + report.deprecationWarning( + i"overriding val parameter ${other.showLocated} is deprecated, will be illegal in a future version", + member.srcPos) else if !other.isExperimental && member.hasAnnotation(defn.ExperimentalAnnot) then // (1.12) overrideError("may not override non-experimental member") else if other.hasAnnotation(defn.DeprecatedOverridingAnnot) then diff --git a/tests/neg/i11344.scala b/tests/neg-custom-args/deprecation/i11344.scala similarity index 100% rename from tests/neg/i11344.scala rename to tests/neg-custom-args/deprecation/i11344.scala diff --git a/tests/neg/i16092.scala b/tests/neg-strict/i16092.scala similarity index 89% rename from tests/neg/i16092.scala rename to tests/neg-strict/i16092.scala index c24e030087a2..b86c034c815b 100644 --- a/tests/neg/i16092.scala +++ b/tests/neg-strict/i16092.scala @@ -7,7 +7,7 @@ class Z(val x: X, val t: x.T) { def process(): Unit = x.process(t) } class Evil(x1: X, x2: X, t: x1.T) extends Z(x1, t) { - val x: X = x2 // error breaks connection between x and t + override val x: X = x2 // error breaks connection between x and t } // alarm bells should be ringing by now From b1856e77414baa4432f741efcaa5f1b8c3f98425 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 25 Sep 2022 17:53:33 +0200 Subject: [PATCH 3/8] Drop checkInit tests that cause deprecation warnings --- tests/init/neg/override13.scala | 13 ------------- tests/init/neg/override16.scala | 23 ----------------------- 2 files changed, 36 deletions(-) delete mode 100644 tests/init/neg/override13.scala delete mode 100644 tests/init/neg/override16.scala diff --git a/tests/init/neg/override13.scala b/tests/init/neg/override13.scala deleted file mode 100644 index 172fdc2709c8..000000000000 --- a/tests/init/neg/override13.scala +++ /dev/null @@ -1,13 +0,0 @@ -abstract class A { - val x = f - - def f: Int -} - -class B(val y: Int) extends A { - def f: Int = y -} - -class C extends B(5) { - override val y: Int = 10 // error -} diff --git a/tests/init/neg/override16.scala b/tests/init/neg/override16.scala deleted file mode 100644 index 6e674faf57b1..000000000000 --- a/tests/init/neg/override16.scala +++ /dev/null @@ -1,23 +0,0 @@ -class A(n: Int) { - val x = n - - def f: Int = x * x -} - -class B(val a: A) { - val b = a.f -} - -class C(override val a: A) extends B(new A(10)) // ok - -class M(val a: A) - -class N(override val a: A) extends M(new A(10)) - -class X(val a: A) { - a.f -} - -class Y extends X(new A(10)) { - override val a: A = ??? // error -} From d1862de57f2dd5d37ae1302fc9ef0466f8e0af9e Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 25 Sep 2022 18:24:02 +0200 Subject: [PATCH 4/8] Fix specs2 code to be future proof --- community-build/community-projects/specs2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/community-build/community-projects/specs2 b/community-build/community-projects/specs2 index e1ae96e7a55f..2bfe446a4e91 160000 --- a/community-build/community-projects/specs2 +++ b/community-build/community-projects/specs2 @@ -1 +1 @@ -Subproject commit e1ae96e7a55fed2268f9ccd391687a5ac96ee4df +Subproject commit 2bfe446a4e9122b1122a7e13a3d100b3749b8630 From dd85d5753cb924516aa32521924db7dd3e79a3b8 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 26 Sep 2022 18:24:42 +0200 Subject: [PATCH 5/8] Allow indirect inherited accessors --- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 11 ++++++++--- tests/pos/i16092.scala | 13 +++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 9cf7347645c1..9feff57ae806 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -516,9 +516,7 @@ object RefChecks { overrideError(i"needs to be declared with @targetName(${"\""}${other.targetName}${"\""}) so that external names match") else overrideError("cannot have a @targetName annotation since external names would be different") - else if other.is(ParamAccessor) - && !(member.is(ParamAccessor) && ParamForwarding.inheritedAccessor(member) == other) - then // (1.13) + else if other.is(ParamAccessor) && !isInheritedAccessor(member, other) then // (1.13) if sourceVersion.isAtLeast(`future`) then overrideError(i"cannot override val parameter ${other.showLocated}") else @@ -531,6 +529,13 @@ object RefChecks { overrideDeprecation("", member, other, "removed or renamed") end checkOverride + def isInheritedAccessor(mbr: Symbol, other: Symbol): Boolean = + mbr.is(ParamAccessor) + && { + val next = ParamForwarding.inheritedAccessor(mbr) + next == other || isInheritedAccessor(next, other) + } + OverridingPairsChecker(clazz, self).checkAll(checkOverride) printMixinOverrideErrors() diff --git a/tests/pos/i16092.scala b/tests/pos/i16092.scala index 4d0f3e539ca7..f092a4250eb7 100644 --- a/tests/pos/i16092.scala +++ b/tests/pos/i16092.scala @@ -3,3 +3,16 @@ class B(override val x: Int) extends A(x) class C(x: Int) extends A(x) case class D(override val x: Int) extends C(x) + +// The following is extracted from akka: +trait LogEvent { + def cause: Throwable +} + +/** + * For ERROR Logging + */ +case class Error(override val cause: Throwable) extends LogEvent +class Error2(override val cause: Throwable) extends Error(cause) +class Error3(override val cause: Throwable) extends Error2(cause) + From a07d9e642e69d5d01cc91adda1d85d7b3f58e4bf Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 26 Sep 2022 18:25:56 +0200 Subject: [PATCH 6/8] Fix remaining CB projects Temporarily, always report an error instead of a deprecation warning to verify that projects compile. This will be reverted in the next commit. --- community-build/community-projects/akka | 2 +- community-build/community-projects/scalacheck | 2 +- community-build/community-projects/spire | 2 +- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/community-build/community-projects/akka b/community-build/community-projects/akka index ed97fe5233cb..7f5115ebc9cd 160000 --- a/community-build/community-projects/akka +++ b/community-build/community-projects/akka @@ -1 +1 @@ -Subproject commit ed97fe5233cbda2da02abad50d48c310077b313c +Subproject commit 7f5115ebc9cde408433040f11834f5218b4a3357 diff --git a/community-build/community-projects/scalacheck b/community-build/community-projects/scalacheck index 0ac8005753ab..fbfaabd7b628 160000 --- a/community-build/community-projects/scalacheck +++ b/community-build/community-projects/scalacheck @@ -1 +1 @@ -Subproject commit 0ac8005753ab98b6494fd631502201b97a103638 +Subproject commit fbfaabd7b628e9b0d8f78ed8a91a0672cf56ba15 diff --git a/community-build/community-projects/spire b/community-build/community-projects/spire index 6869620975fa..7f630c0209e3 160000 --- a/community-build/community-projects/spire +++ b/community-build/community-projects/spire @@ -1 +1 @@ -Subproject commit 6869620975fa84dd1ef78c2711d6a4f8197060ae +Subproject commit 7f630c0209e327bdc782ade2210d8e4b916fddcc diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 9feff57ae806..f031dc686426 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -517,7 +517,7 @@ object RefChecks { else overrideError("cannot have a @targetName annotation since external names would be different") else if other.is(ParamAccessor) && !isInheritedAccessor(member, other) then // (1.13) - if sourceVersion.isAtLeast(`future`) then + if true || sourceVersion.isAtLeast(`future`) then overrideError(i"cannot override val parameter ${other.showLocated}") else report.deprecationWarning( From f43e98ef7b81bd3b6a6c05a5a93bfe8ca394f2b0 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 26 Sep 2022 18:26:54 +0200 Subject: [PATCH 7/8] Emit errors again only under -source future --- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index f031dc686426..9feff57ae806 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -517,7 +517,7 @@ object RefChecks { else overrideError("cannot have a @targetName annotation since external names would be different") else if other.is(ParamAccessor) && !isInheritedAccessor(member, other) then // (1.13) - if true || sourceVersion.isAtLeast(`future`) then + if sourceVersion.isAtLeast(`future`) then overrideError(i"cannot override val parameter ${other.showLocated}") else report.deprecationWarning( From fb75d961475b4b321206b7e58dcf1ab86f16b683 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 26 Sep 2022 23:39:32 +0200 Subject: [PATCH 8/8] Update compiler/src/dotty/tools/dotc/typer/RefChecks.scala --- compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 9feff57ae806..3ca15ab976dd 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -265,7 +265,7 @@ object RefChecks { * 1.11. If O is a Scala-2 macro, M must be a Scala-2 macro. * 1.12. If O is non-experimental, M must be non-experimental. * 1.13 Under -source future, if O is a val parameter, M must be a val parameter - * that passes its on to O. + * that passes its value on to O. * 2. Check that only abstract classes have deferred members * 3. Check that concrete classes do not have deferred definitions * that are not implemented in a subclass.