From 05e861b547294c9150b9d7073e3b526959670d35 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Wed, 18 Jan 2023 11:11:59 +0100 Subject: [PATCH] Disallow mixins where super calls bind to vals Super calls in traits are bound when the trait is mixed into a class. Disallow mixin compositions where the target of a super call is a value (not a method). --- .../scala/tools/nsc/transform/Mixin.scala | 2 ++ test/files/neg/t12715.check | 7 ++++++ test/files/neg/t12715.scala | 23 +++++++++++++++++++ test/files/neg/t12715b.check | 4 ++++ test/files/neg/t12715b.scala | 19 +++++++++++++++ 5 files changed, 55 insertions(+) create mode 100644 test/files/neg/t12715.check create mode 100644 test/files/neg/t12715.scala create mode 100644 test/files/neg/t12715b.check create mode 100644 test/files/neg/t12715b.scala diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 98b8e0cbbad1..92a5b15b12cf 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -357,6 +357,8 @@ abstract class Mixin extends Transform with ast.TreeDSL with AccessorSynthesis { case alias1 => registerRequiredDirectInterface(alias1, clazz, parent => s"Unable to implement a super accessor required by trait ${mixinClass.name} unless $parent is directly extended by $clazz.") + if (alias1.isValue && !alias1.isMethod || alias1.isAccessor) + reporter.error(clazz.pos, s"parent $mixinClass has a super call to method ${mixinMember.alias.fullNameString}, which binds to the value ${alias1.fullNameString}. Super calls can only target methods.") superAccessor.asInstanceOf[TermSymbol] setAlias alias1 } } diff --git a/test/files/neg/t12715.check b/test/files/neg/t12715.check new file mode 100644 index 000000000000..729af9c43246 --- /dev/null +++ b/test/files/neg/t12715.check @@ -0,0 +1,7 @@ +t12715.scala:21: error: parent trait E has a super call to method B.f, which binds to the value D.f. Super calls can only target methods. +object O1 extends B with C with D with E + ^ +t12715.scala:22: error: parent trait E has a super call to method B.f, which binds to the value C.f. Super calls can only target methods. +object O2 extends B with C with E with D + ^ +2 errors diff --git a/test/files/neg/t12715.scala b/test/files/neg/t12715.scala new file mode 100644 index 000000000000..e3769141b4c4 --- /dev/null +++ b/test/files/neg/t12715.scala @@ -0,0 +1,23 @@ +trait A { + def f: String +} + +trait B extends A { + def f = "B"; +} + +trait C extends A { + override val f = "C" +} + +trait D extends C { + override val f = "D" +} + +trait E extends A with B { + def d = super.f +} + +object O1 extends B with C with D with E +object O2 extends B with C with E with D +object O3 extends B with E with C with D diff --git a/test/files/neg/t12715b.check b/test/files/neg/t12715b.check new file mode 100644 index 000000000000..3cdb24a74351 --- /dev/null +++ b/test/files/neg/t12715b.check @@ -0,0 +1,4 @@ +t12715b.scala:17: error: parent trait D has a super call to method B.f, which binds to the value C.f. Super calls can only target methods. + new A(10.0f) with C with D {} + ^ +1 error diff --git a/test/files/neg/t12715b.scala b/test/files/neg/t12715b.scala new file mode 100644 index 000000000000..9d89233dc85f --- /dev/null +++ b/test/files/neg/t12715b.scala @@ -0,0 +1,19 @@ +trait B { + def f: Float = 1.0f +} + +class A(override val f: Float) extends B + +trait C extends B { + abstract override val f = super.f + 100.0f +} + +trait D extends B { + abstract override val f = super.f + 1000.0f +} + +object Test { + def main(args: Array[String]): Unit = { + new A(10.0f) with C with D {} + } +}