Skip to content

Commit eae8831

Browse files
@publicInBinary override spec change (#19296)
Followup of #18402 (see #18402 (comment)). This was split from the main PR due to the blocker described in #18402 (comment). During the Dotty meeting, we decided to merge #18402 without the second commit ([Require @publicInBinary on overrides](34f3dee)). If we manage to fix this issue before 3.4.0-RC1 we will include it there, otherwise it will be part of 3.4.0-RC2.
2 parents 8d9da73 + 7205496 commit eae8831

File tree

6 files changed

+26
-11
lines changed

6 files changed

+26
-11
lines changed

Diff for: compiler/src/dotty/tools/dotc/core/SymDenotations.scala

+1-4
Original file line numberDiff line numberDiff line change
@@ -1033,10 +1033,7 @@ object SymDenotations {
10331033

10341034
/** Is this a member that will become public in the generated binary */
10351035
def hasPublicInBinary(using Context): Boolean =
1036-
isTerm && (
1037-
hasAnnotation(defn.PublicInBinaryAnnot) ||
1038-
allOverriddenSymbols.exists(sym => sym.hasAnnotation(defn.PublicInBinaryAnnot))
1039-
)
1036+
isTerm && hasAnnotation(defn.PublicInBinaryAnnot)
10401037

10411038
/** ()T and => T types should be treated as equivalent for this symbol.
10421039
* Note: For the moment, we treat Scala-2 compiled symbols as loose matching,

Diff for: compiler/src/dotty/tools/dotc/typer/RefChecks.scala

+7-4
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,10 @@ object RefChecks {
298298
* 1.9. If M is erased, O is erased. If O is erased, M is erased or inline.
299299
* 1.10. If O is inline (and deferred, otherwise O would be final), M must be inline
300300
* 1.11. If O is a Scala-2 macro, M must be a Scala-2 macro.
301-
* 1.12. If O is non-experimental, M must be non-experimental.
302-
* 1.13 Under -source future, if O is a val parameter, M must be a val parameter
301+
* 1.12. Under -source future, if O is a val parameter, M must be a val parameter
303302
* that passes its value on to O.
303+
* 1.13. If O is non-experimental, M must be non-experimental.
304+
* 1.14. If O has @publicInBinary, M must have @publicInBinary.
304305
* 2. Check that only abstract classes have deferred members
305306
* 3. Check that concrete classes do not have deferred definitions
306307
* that are not implemented in a subclass.
@@ -571,13 +572,15 @@ object RefChecks {
571572
overrideError(i"needs to be declared with @targetName(${"\""}${other.targetName}${"\""}) so that external names match")
572573
else
573574
overrideError("cannot have a @targetName annotation since external names would be different")
574-
else if other.is(ParamAccessor) && !isInheritedAccessor(member, other) then // (1.13)
575+
else if other.is(ParamAccessor) && !isInheritedAccessor(member, other) then // (1.12)
575576
report.errorOrMigrationWarning(
576577
em"cannot override val parameter ${other.showLocated}",
577578
member.srcPos,
578579
MigrationVersion.OverrideValParameter)
579-
else if !other.isExperimental && member.hasAnnotation(defn.ExperimentalAnnot) then // (1.12)
580+
else if !other.isExperimental && member.hasAnnotation(defn.ExperimentalAnnot) then // (1.13)
580581
overrideError("may not override non-experimental member")
582+
else if !member.hasAnnotation(defn.PublicInBinaryAnnot) && other.hasAnnotation(defn.PublicInBinaryAnnot) then // (1.14)
583+
overrideError("also needs to be declared with @publicInBinary")
581584
else if other.hasAnnotation(defn.DeprecatedOverridingAnnot) then
582585
overrideDeprecation("", member, other, "removed or renamed")
583586
end checkOverride

Diff for: library/src/scala/annotation/publicInBinary.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package scala.annotation
22

3-
/** A binary API is a definition that is annotated with `@publicInBinary` or overrides a definition annotated with `@publicInBinary`.
3+
/** A binary API is a definition that is annotated with `@publicInBinary`.
44
* This annotation can be placed on `def`, `val`, `lazy val`, `var`, class constructors, `object`, and `given` definitions.
55
* A binary API will be publicly available in the bytecode. Tools like TASTy MiMa will take this into account to check
66
* compatibility.

Diff for: tests/neg/publicInBinaryOverride.check

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- [E164] Declaration Error: tests/neg/publicInBinaryOverride.scala:8:15 -----------------------------------------------
2+
8 | override def f(): Unit = () // error
3+
| ^
4+
| error overriding method f in class A of type (): Unit;
5+
| method f of type (): Unit also needs to be declared with @publicInBinary

Diff for: tests/neg/publicInBinaryOverride.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import scala.annotation.publicInBinary
2+
3+
class A:
4+
@publicInBinary def f(): Unit = ()
5+
@publicInBinary def g(): Unit = ()
6+
7+
class B extends A:
8+
override def f(): Unit = () // error
9+
@publicInBinary override def g(): Unit = ()

Diff for: tests/run/publicInBinary/Lib_1.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ class Foo(@publicInBinary private[Foo] val paramVal: Int, @publicInBinary privat
2121
paramVal + paramVar + protectedVal + packagePrivateVal + protectedVar + packagePrivateVar
2222

2323
class Bar() extends Foo(3, 3):
24+
@publicInBinary
2425
override protected val protectedVal: Int = 2
25-
26+
@publicInBinary
2627
override private[foo] val packagePrivateVal: Int = 2
2728

2829
inline def bar: Int = protectedVal + packagePrivateVal
2930

3031
class Baz() extends Foo(4, 4):
31-
@publicInBinary // TODO warn? Not needed because Foo.protectedVal is already @publicInBinary
32+
@publicInBinary
3233
override protected val protectedVal: Int = 2
3334

3435
@publicInBinary

0 commit comments

Comments
 (0)