From 954fdcdf0271ee990c7ccd1829f9c4891f1c1daf Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 12 Jul 2024 12:01:55 +0200 Subject: [PATCH] Check that overrides don't change the @unbox status of their parameters --- .../dotty/tools/dotc/cc/CheckCaptures.scala | 17 ++++++++++++++- .../dotty/tools/dotc/typer/RefChecks.scala | 3 +++ .../captures/unbox-overrides.check | 21 +++++++++++++++++++ .../captures/unbox-overrides.scala | 15 +++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/neg-custom-args/captures/unbox-overrides.check create mode 100644 tests/neg-custom-args/captures/unbox-overrides.scala diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala index a83c32eb1284..30dfe8f8881c 100644 --- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala +++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala @@ -22,7 +22,7 @@ import CaptureSet.{withCaptureSetsExplained, IdempotentCaptRefMap, CompareResult import CCState.* import StdNames.nme import NameKinds.{DefaultGetterName, WildcardParamName, UniqueNameKind} -import reporting.{trace, Message} +import reporting.{trace, Message, OverrideError} /** The capture checker */ object CheckCaptures: @@ -1271,6 +1271,21 @@ class CheckCaptures extends Recheck, SymTransformer: !setup.isPreCC(overriding) && !setup.isPreCC(overridden) override def checkInheritedTraitParameters: Boolean = false + + /** Check that overrides don't change the @unbox status of their parameters */ + override def additionalChecks(member: Symbol, other: Symbol)(using Context): Unit = + for + (params1, params2) <- member.rawParamss.lazyZip(other.rawParamss) + (param1, param2) <- params1.lazyZip(params2) + do + if param1.hasAnnotation(defn.UnboxAnnot) != param2.hasAnnotation(defn.UnboxAnnot) then + report.error( + OverrideError( + i"has a parameter ${param1.name} with different @unbox status than the corresponding parameter in the overridden definition", + self, member, other, self.memberInfo(member), self.memberInfo(other) + ), + if member.owner == clazz then member.srcPos else clazz.srcPos + ) end OverridingPairsCheckerCC def traverse(t: Tree)(using Context) = diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index cb1aea27c444..2601bfb42074 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -250,12 +250,15 @@ object RefChecks { */ def needsCheck(overriding: Symbol, overridden: Symbol)(using Context): Boolean = true + protected def additionalChecks(overriding: Symbol, overridden: Symbol)(using Context): Unit = () + private val subtypeChecker: (Type, Type) => Context ?=> Boolean = this.checkSubType def checkAll(checkOverride: ((Type, Type) => Context ?=> Boolean, Symbol, Symbol) => Unit) = while hasNext do if needsCheck(overriding, overridden) then checkOverride(subtypeChecker, overriding, overridden) + additionalChecks(overriding, overridden) next() // The OverridingPairs cursor does assume that concrete overrides abstract diff --git a/tests/neg-custom-args/captures/unbox-overrides.check b/tests/neg-custom-args/captures/unbox-overrides.check new file mode 100644 index 000000000000..b9a3be7bffbc --- /dev/null +++ b/tests/neg-custom-args/captures/unbox-overrides.check @@ -0,0 +1,21 @@ +-- [E164] Declaration Error: tests/neg-custom-args/captures/unbox-overrides.scala:8:6 ---------------------------------- +8 | def foo(x: C): C // error + | ^ + |error overriding method foo in trait A of type (x: C): C; + | method foo of type (x: C): C has a parameter x with different @unbox status than the corresponding parameter in the overridden definition + | + | longer explanation available when compiling with `-explain` +-- [E164] Declaration Error: tests/neg-custom-args/captures/unbox-overrides.scala:9:6 ---------------------------------- +9 | def bar(@unbox x: C): C // error + | ^ + |error overriding method bar in trait A of type (x: C): C; + | method bar of type (x: C): C has a parameter x with different @unbox status than the corresponding parameter in the overridden definition + | + | longer explanation available when compiling with `-explain` +-- [E164] Declaration Error: tests/neg-custom-args/captures/unbox-overrides.scala:15:15 -------------------------------- +15 |abstract class C extends A[C], B2 // error + | ^ + |error overriding method foo in trait A of type (x: C): C; + | method foo in trait B2 of type (x: C): C has a parameter x with different @unbox status than the corresponding parameter in the overridden definition + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/captures/unbox-overrides.scala b/tests/neg-custom-args/captures/unbox-overrides.scala new file mode 100644 index 000000000000..5abb5013bfbe --- /dev/null +++ b/tests/neg-custom-args/captures/unbox-overrides.scala @@ -0,0 +1,15 @@ +import caps.unbox + +trait A[X]: + def foo(@unbox x: X): X + def bar(x: X): X + +trait B extends A[C]: + def foo(x: C): C // error + def bar(@unbox x: C): C // error + +trait B2: + def foo(x: C): C + def bar(@unbox x: C): C + +abstract class C extends A[C], B2 // error