Skip to content

Commit 82b3e13

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 53c771a commit 82b3e13

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
@@ -35,6 +35,9 @@ object PrepareInlineable {
3535
def makeInlineable(tree: Tree)(using Context): Tree =
3636
ctx.property(InlineAccessorsKey).get.makeInlineable(tree)
3737

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

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

5859
def useBinaryAPI: Boolean
5960

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

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

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

@@ -210,6 +222,16 @@ object PrepareInlineable {
210222
}
211223
}
212224

225+
/** Create an inline accessor for this definition. */
226+
def makePrivateBinaryAPIAccessor(sym: Symbol)(using Context): Unit =
227+
assert(sym.is(Private))
228+
if !sym.owner.is(Trait) then
229+
val ref = tpd.ref(sym).asInstanceOf[RefTree]
230+
val insertPrivateBinaryAPIAccessors = new InsertPrivateBinaryAPIAccessors()
231+
val accessor = insertPrivateBinaryAPIAccessors.useAccessor(ref)
232+
if sym.is(Mutable) then
233+
insertPrivateBinaryAPIAccessors.useSetter(accessor)
234+
213235
/** Adds accessors for all non-public term members accessed
214236
* from `tree`. Non-public type members are currently left as they are.
215237
* 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
@@ -2429,6 +2429,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
24292429
}
24302430
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
24312431
postProcessInfo(sym)
2432+
binaryAPI(sym)
24322433
vdef1.setDefTree
24332434
}
24342435

@@ -2532,6 +2533,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25322533
val ddef2 = assignType(cpy.DefDef(ddef)(name, paramss1, tpt1, rhs1), sym)
25332534

25342535
postProcessInfo(sym)
2536+
binaryAPI(sym)
25352537
ddef2.setDefTree
25362538
//todo: make sure dependent method types do not depend on implicits or by-name params
25372539
}
@@ -2545,6 +2547,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
25452547
if !sym.is(Module) && !sym.isConstructor && sym.info.finalResultType.isErasedClass then
25462548
sym.setFlag(Erased)
25472549

2550+
/** Generate inline accessors for definitions annotated with @inlineAccessible */
2551+
def binaryAPI(sym: Symbol)(using Context): Unit =
2552+
if !ctx.isAfterTyper && !sym.is(Param) && sym.is(Private) && sym.hasAnnotation(defn.BinaryAPIAnnot) then
2553+
PrepareInlineable.makePrivateBinaryAPIAccessor(sym)
2554+
25482555
def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(using Context): Tree = {
25492556
val TypeDef(name, rhs) = tdef
25502557
completeAnnotations(tdef, sym)

0 commit comments

Comments
 (0)