Skip to content

Commit 971ca5e

Browse files
committed
Support @binaryAPI on private[this] definitions
In this case the annotation will generate a public accessor (and setter). This accessor has a consistent name that avoids clashes (`<className>$inline$<definitionName>`). It will have the same name as a private accessor that would have been generate in a non final class by the old inline accessor generation.
1 parent 0537a3b commit 971ca5e

File tree

9 files changed

+210
-48
lines changed

9 files changed

+210
-48
lines changed

compiler/src/dotty/tools/dotc/inlines/PrepareInlineable.scala

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ object PrepareInlineable {
3434
def makeInlineable(tree: Tree)(using Context): Tree =
3535
ctx.property(InlineAccessorsKey).get.makeInlineable(tree)
3636

37+
def makePrivateBinaryAPIAccessor(sym: Symbol)(using Context): Unit =
38+
ctx.property(InlineAccessorsKey).get.makePrivateBinaryAPIAccessor(sym)
39+
3740
def addAccessorDefs(cls: Symbol, body: List[Tree])(using Context): List[Tree] =
3841
ctx.property(InlineAccessorsKey) match
3942
case Some(inlineAccessors) => inlineAccessors.addAccessorDefs(cls, body)
@@ -50,15 +53,14 @@ object PrepareInlineable {
5053
case _ => false
5154
}
5255

53-
/** A tree map which inserts accessors for non-public term members accessed from inlined code.
54-
*/
55-
abstract class MakeInlineableMap(val inlineSym: Symbol) extends TreeMap with Insert {
56+
trait InsertInlineAccessors extends Insert {
5657

5758
def useBinaryAPI: Boolean
5859

59-
def accessorNameOf(name: TermName, site: Symbol)(using Context): TermName =
60-
val accName = InlineAccessorName(name)
61-
if site.isExtensibleClass then accName.expandedName(site) else accName
60+
def accessorNameOf(accessed: Symbol, site: Symbol)(using Context): TermName =
61+
val accName = InlineAccessorName(accessed.name.asTermName)
62+
if site.isExtensibleClass || useBinaryAPI then accName.expandedName(site)
63+
else accName
6264

6365
/** A definition needs an accessor if it is private, protected, or qualified private
6466
* and it is not part of the tree that gets inlined. The latter test is implemented
@@ -73,11 +75,21 @@ object PrepareInlineable {
7375
def needsAccessor(sym: Symbol)(using Context): Boolean =
7476
sym.isTerm &&
7577
(sym.isOneOf(AccessFlags) || sym.privateWithin.exists) &&
76-
(!useBinaryAPI || !sym.isBinaryAPI) &&
77-
!sym.isContainedIn(inlineSym) &&
78+
(!useBinaryAPI || !sym.isBinaryAPI || (sym.is(Private) && !sym.owner.is(Trait))) &&
7879
!(sym.isStableMember && sym.info.widenTermRefExpr.isInstanceOf[ConstantType]) &&
7980
!sym.isInlineMethod &&
8081
(Inlines.inInlineMethod || StagingContext.level > 0)
82+
}
83+
84+
class InsertPrivateBinaryAPIAccessors extends InsertInlineAccessors:
85+
def useBinaryAPI: Boolean = true
86+
87+
/** A tree map which inserts accessors for non-public term members accessed from inlined code.
88+
*/
89+
abstract class MakeInlineableMap(val inlineSym: Symbol) extends TreeMap with InsertInlineAccessors {
90+
91+
override def needsAccessor(sym: Symbol)(using Context): Boolean =
92+
!sym.isContainedIn(inlineSym) && super.needsAccessor(sym)
8193

8294
def preTransform(tree: Tree)(using Context): Tree
8395

@@ -216,6 +228,16 @@ object PrepareInlineable {
216228
}
217229
}
218230

231+
/** Create an inline accessor for this definition. */
232+
def makePrivateBinaryAPIAccessor(sym: Symbol)(using Context): Unit =
233+
assert(sym.is(Private))
234+
if !sym.owner.is(Trait) then
235+
val ref = tpd.ref(sym).asInstanceOf[RefTree]
236+
val insertPrivateBinaryAPIAccessors = new InsertPrivateBinaryAPIAccessors()
237+
val accessor = insertPrivateBinaryAPIAccessors.useAccessor(ref)
238+
if sym.is(Mutable) then
239+
insertPrivateBinaryAPIAccessors.useSetter(accessor)
240+
219241
/** Adds accessors for all non-public term members accessed
220242
* from `tree`. Non-public type members are currently left as they are.
221243
* This means that references to a private type will lead to typing failures

compiler/src/dotty/tools/dotc/transform/AccessProxies.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ abstract class AccessProxies {
6767
import ast.tpd._
6868

6969
/** The name of the accessor for definition with given `name` in given `site` */
70-
def accessorNameOf(name: TermName, site: Symbol)(using Context): TermName
70+
def accessorNameOf(accessed: Symbol, site: Symbol)(using Context): TermName
7171
def needsAccessor(sym: Symbol)(using Context): Boolean
7272

7373
def ifNoHost(reference: RefTree)(using Context): Tree = {
@@ -136,7 +136,7 @@ abstract class AccessProxies {
136136
if (accessorClass.exists) {
137137
if accessorClass.is(Package) then
138138
accessorClass = ctx.owner.topLevelClass
139-
val accessorName = accessorNameOf(accessed.name, accessorClass)
139+
val accessorName = accessorNameOf(accessed, accessorClass)
140140
val accessorInfo =
141141
accessed.info.ensureMethodic.asSeenFrom(accessorClass.thisType, accessed.owner)
142142
val accessor = accessorSymbol(accessorClass, accessorName, accessorInfo, accessed)

compiler/src/dotty/tools/dotc/transform/ProtectedAccessors.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class ProtectedAccessors extends MiniPhase {
6464

6565
private class Accessors extends AccessProxies {
6666
val insert: Insert = new Insert {
67-
def accessorNameOf(name: TermName, site: Symbol)(using Context): TermName = ProtectedAccessorName(name)
67+
def accessorNameOf(accessed: Symbol, site: Symbol)(using Context): TermName = ProtectedAccessorName(accessed.name.asTermName)
6868
def needsAccessor(sym: Symbol)(using Context) = ProtectedAccessors.needsAccessor(sym)
6969

7070
override def ifNoHost(reference: RefTree)(using Context): Tree = {

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,6 @@ object Checking {
530530
if sym.is(Enum) then fail(em"@binaryAPI cannot be used on enum definitions.")
531531
else if sym.isType && !sym.is(Module) && !(sym.is(Given) || sym.companionModule.is(Given)) then fail(em"@binaryAPI cannot be used on ${sym.showKind} definitions")
532532
else if !sym.owner.isClass && !(sym.is(Param) && sym.owner.isConstructor) then fail(em"@binaryAPI cannot be used on local definitions.")
533-
else if sym.is(Private) then fail(em"@binaryAPI cannot be used on private definitions.\n\nCould use private[${sym.owner.name}] or protected instead.")
534533
if (sym.hasAnnotation(defn.NativeAnnot)) {
535534
if (!sym.is(Deferred))
536535
fail(NativeMembersMayNotHaveImplementation(sym))

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,6 +2347,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
23472347
}
23482348
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
23492349
postProcessInfo(sym)
2350+
binaryAPI(sym)
23502351
vdef1.setDefTree
23512352
}
23522353

@@ -2450,6 +2451,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
24502451
val ddef2 = assignType(cpy.DefDef(ddef)(name, paramss1, tpt1, rhs1), sym)
24512452

24522453
postProcessInfo(sym)
2454+
binaryAPI(sym)
24532455
ddef2.setDefTree
24542456
//todo: make sure dependent method types do not depend on implicits or by-name params
24552457
}
@@ -2463,6 +2465,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
24632465
if !sym.is(Module) && !sym.isConstructor && sym.info.finalResultType.isErasedClass then
24642466
sym.setFlag(Erased)
24652467

2468+
/** Generate inline accessors for definitions annotated with @inlineAccessible */
2469+
def binaryAPI(sym: Symbol)(using Context): Unit =
2470+
if !ctx.isAfterTyper && !sym.is(Param) && sym.is(Private) && sym.hasAnnotation(defn.BinaryAPIAnnot) then
2471+
PrepareInlineable.makePrivateBinaryAPIAccessor(sym)
2472+
24662473
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = {
24672474
val TypeDef(name, rhs) = tdef
24682475
completeAnnotations(tdef, sym)

0 commit comments

Comments
 (0)