-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add @publicInBinary
annotation and -WunstableInlineAccessors
linting flag
#18402
Conversation
138aae3
to
b579c5a
Compare
@binaryAPI
annotation@binaryAPI
annotation and -WunstableInlineAccessors
linting flag
b579c5a
to
a696e00
Compare
a696e00
to
addd6c8
Compare
@binaryAPI
annotation and -WunstableInlineAccessors
linting flag@publicInBinary
annotation and -WunstableInlineAccessors
linting flag
c203441
to
1327818
Compare
44bd552
to
a077c15
Compare
8095426
to
e029796
Compare
eb7e18d
to
6ce6ab4
Compare
def hasPublicInBinary(using Context): Boolean = | ||
isTerm && ( | ||
hasAnnotation(defn.PublicInBinaryAnnot) || | ||
allOverriddenSymbols.exists(sym => sym.hasAnnotation(defn.PublicInBinaryAnnot)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, allOverriddenSymbols
might be expensive and no other annotations is inherited as far as I know, so I'd really prefer if we were more strict in the implementation (the sip is still experimental, so the implementation and spec don't need to exactly match yet)
package scala.annotation | ||
|
||
/** A binary API is a definition that is annotated with `@publicInBinary` or overrides a definition annotated with `@publicInBinary`. | ||
* This annotation can be placed on `def`, `val`, `lazy val`, `var`, `object`, and `given` definitions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The SIP also says that class constructors are supported, but this isn't mentioned here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added doc
* | ||
* This can be used to access private[T]/protected definitions within inline definitions. | ||
* | ||
* Removing this annotation from a non-public definition is a binary incompatible change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding it is also binary incompatible since it means some accessors won't be generated, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Added doc.
|
||
/** A binary API is a definition that is annotated with `@publicInBinary` or overrides a definition annotated with `@publicInBinary`. | ||
* This annotation can be placed on `def`, `val`, `lazy val`, `var`, `object`, and `given` definitions. | ||
* A binary API will be publicly available in the bytecode. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we clarify the behavior of this annotation in this documentation? As far as I can tell, we've established that this annotation doesn't change the bytecode representation of the thing that is annotated, because everything that is allowed to be annotated will already be public, so the documentation as-is might be confusing. Instead the effect of this annotation is:
- no unnecessary accessors will be generated/used (which I guess should be considered a bug-fix since these accessors were never actually necessary and could break compilation?)
- Tools like mima/tasty-mima can rely on this annotation to determine if it is safe for Scala binary-compatibility to change/remove a method that is public in the bytecode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rewrote part of the doc
|
||
protected def checkUnstableAccessor(accessedTree: Tree, accessor: Symbol)(using Context): Unit = | ||
if ctx.settings.WunstableInlineAccessors.value then | ||
val accessorTree = accessorDef(accessor, accessedTree.symbol) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something I'm now wondering: if this annotation doesn't in fact change the bytecode we generate, then why do we bother going through the inline accessor when calling non-annotated protected/package-private methods? Couldn't we always make a direct call even if the method isn't annotated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need the annotation as a way to tell MiMa that this protected/package-private method can be used from outside the scope where it is defined.
We might be able to do this optimization once we have established -WunstableInlineAccessors
and can break the old accessors. In this case we would still need to warn if that definition is not annotated with @publicInBinary
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could start using some of those package-private methods directly now but still generate the accessor. I will look into it after this PR and after the 3.4 release.
2f525de
to
1b3cc3a
Compare
1b3cc3a
to
e5e3dcf
Compare
The commit (9789d51) that changes the overriding spec is causing failures in
|
No clue, but instead of doing this in Typer, I would recommend adding a case |
Introduces [SIP-52](scala/improvement-proposals#58) as experimental feature. A binary API is a definition that is annotated with `@publicInBinary` or overrides a definition annotated with `@publicInBinary`. This annotation can be placed on `def`, `val`, `lazy val`, `var`, `object`, and `given` definitions. A binary API will be publicly available in the bytecode. It cannot be used on `private`/`private[this]` definitions. This is useful in combination with inline definitions. If an inline definition refers to a private/protected definition marked as `@publicInBinary` it does not need to use an accessor. We still generate the accessors for binary compatibility but do not use them. If the linting option `-WunstableInlineAccessors` is enabled, then a warning will be emitted if an inline accessor is generated. The warning will guide the user to the use of `@publicInBinary`.
9789d51
to
583d5ae
Compare
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.
* Change suggestion scala/scala3#18402 (comment) * Changed in scala/scala3@eae8831
* Change suggestion scala/scala3#18402 (comment) * Changed in scala/scala3@eae8831
Introduces SIP-52 as an experimental feature.
Fixes #16983
@publicInBinary
A binary API is a definition that is annotated with
@publicInBinary
or overrides a definition annotated with@publicInBinary
. This annotation can be placed ondef
,val
,lazy val
,var
,object
, andgiven
definitions. A binary API will be publicly available in the bytecode. It cannot be used onprivate
/private[this]
definitions.Interaction with inline
This is useful in combination with inline definitions. If an inline definition refers to a private/protected definition marked as
@publicInBinary
it does not need to use an accessor. We still generate the accessors for binary compatibility but do not use them.-WunstableInlineAccessors
If the linting option
-WunstableInlineAccessors
is enabled, then a warning will be emitted if an inline accessor is generated. The warning will guide the user to the use of@publicInBinary
.