Skip to content

Commit

Permalink
Require @publicInBinary on overrides
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Dec 14, 2023
1 parent e5e3dcf commit 1b3cc3a
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 7 deletions.
5 changes: 1 addition & 4 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1033,10 +1033,7 @@ object SymDenotations {

/** Is this a member that will become public in the generated binary */
def hasPublicInBinary(using Context): Boolean =
isTerm && (
hasAnnotation(defn.PublicInBinaryAnnot) ||
allOverriddenSymbols.exists(sym => sym.hasAnnotation(defn.PublicInBinaryAnnot))
)
isTerm && hasAnnotation(defn.PublicInBinaryAnnot)

/** ()T and => T types should be treated as equivalent for this symbol.
* Note: For the moment, we treat Scala-2 compiled symbols as loose matching,
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,12 @@ object Checking {
else if !sym.owner.isClass && !(sym.is(Param) && sym.owner.isConstructor) then fail(em"@publicInBinary cannot be used on local definitions")
else if sym.is(ParamAccessor) && sym.is(Private) then fail(em"@publicInBinary cannot be non `val` constructor parameters")
else if sym.is(Private) && !sym.privateWithin.exists && !sym.isConstructor then fail(em"@publicInBinary cannot be used on private definitions\n\nConsider using `private[${sym.owner.name}]` or `protected` instead")
else
sym.allOverriddenSymbols.find(sym => sym.hasAnnotation(defn.PublicInBinaryAnnot)) match
case Some(overriddenSym) =>
fail(em"""This definitions ${if sym.is(Override) then "overrides" else "implements"} @publicInBinary ${overriddenSym.showLocated}.
|This definition must also be marked as @publicInBinary.""")
case None => ()
if (sym.hasAnnotation(defn.NativeAnnot)) {
if (!sym.is(Deferred))
fail(NativeMembersMayNotHaveImplementation(sym))
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/annotation/publicInBinary.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package scala.annotation

/** A binary API is a definition that is annotated with `@publicInBinary` or overrides a definition annotated with `@publicInBinary`.
/** A binary API is a definition that is annotated with `@publicInBinary`.
* This annotation can be placed on `def`, `val`, `lazy val`, `var`, class constructors, `object`, and `given` definitions.
* A binary API will be publicly available in the bytecode. Tools like TASTy MiMa will take this into account to check
* compatibility.
Expand Down
5 changes: 3 additions & 2 deletions tests/run/publicInBinary/Lib_1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ class Foo(@publicInBinary private[Foo] val paramVal: Int, @publicInBinary privat
paramVal + paramVar + protectedVal + packagePrivateVal + protectedVar + packagePrivateVar

class Bar() extends Foo(3, 3):
@publicInBinary
override protected val protectedVal: Int = 2

@publicInBinary
override private[foo] val packagePrivateVal: Int = 2

inline def bar: Int = protectedVal + packagePrivateVal

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

@publicInBinary
Expand Down

0 comments on commit 1b3cc3a

Please sign in to comment.