forked from scala/scala3
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generate static inline accessors module
If a class `C` needs inline accessors that would be added top-level or if the accessor is to a static member, we place it in a new invisible module `C$inline$accessors`. If the accessor location in the new scheme is not the same as the previous location, we also generate the old accessor for backward binary compatibility but do not use it. Fixes scala#13215 Fixes scala#15413
- Loading branch information
1 parent
2c893ff
commit f4e4bb0
Showing
32 changed files
with
376 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
compiler/src/dotty/tools/dotc/typer/TopLevelExtensionModules.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package dotty.tools.dotc.typer | ||
|
||
import dotty.tools.dotc.ast.*, untpd.* | ||
import dotty.tools.dotc.core.Contexts.* | ||
import dotty.tools.dotc.core.Flags.* | ||
import dotty.tools.dotc.core.Names.* | ||
import dotty.tools.dotc.core.Scopes.* | ||
import dotty.tools.dotc.core.StdNames.* | ||
import dotty.tools.dotc.core.Symbols.* | ||
|
||
/** Creation of top-level extension modules */ | ||
object TopLevelExtensionModules: | ||
import tpd.* | ||
|
||
/** Creates the symbols for a new extension module associated with the current | ||
* top-level class. These definitions are invisible in the source code. | ||
* | ||
* ```scala | ||
* class C | ||
* // symbols generated by `newAccessorModule("$extension")` | ||
* lazy val C$extension = new C$extension$ | ||
* class C$extension$ | ||
* ``` | ||
* | ||
* @param suffix suffix that will be appended to the name of the top-level class | ||
* @return The class symbol of the new module | ||
*/ | ||
def newAccessorModule(suffix: String)(using Context): ClassSymbol = | ||
val inlineAccessorObjectName: TermName = | ||
assert(suffix.startsWith("$"), "suffix should start with $") | ||
assert(suffix.size > 1, "suffix should start with $ followed by a name") | ||
val fileName = ctx.source.file.name | ||
val sourceName = ctx.owner.topLevelClass.name | ||
(sourceName ++ suffix).toTermName | ||
|
||
val mod = newNormalizedModuleSymbol( | ||
ctx.owner.topLevelClass.owner, | ||
inlineAccessorObjectName, | ||
ModuleValCreationFlags & Invisible, | ||
ModuleClassCreationFlags & Invisible, | ||
List(defn.ObjectClass.typeRef), | ||
newScope, | ||
NoSymbol, | ||
coord = ctx.owner.topLevelClass.span | ||
) | ||
val cls = mod.moduleClass.asClass | ||
cls.enter(newConstructor(cls, Synthetic, Nil, Nil)) | ||
cls | ||
|
||
/** Generate a list with the ValDef and TypeDef trees of an extension module (created with `newAccessorModule`). | ||
* | ||
* ```scala | ||
* // given the moduleClassSym for `C$extension$` and `body` this generates the trees | ||
* lazy val C$extension = new C$extension$ | ||
* class C$extension$: | ||
* <body*> | ||
* ``` | ||
* @param moduleClassSym class symbol of the extension module | ||
* @param body list of definitions in the extension module | ||
*/ | ||
def topLevelModuleDefTree(moduleClassSym: ClassSymbol, body: List[Tree])(using Context): List[Tree] = | ||
assert(moduleClassSym.owner.is(Package)) | ||
val untpdCtr = untpd.DefDef(nme.CONSTRUCTOR, Nil, tpd.TypeTree(defn.UnitClass.typeRef), tpd.EmptyTree) | ||
val ctr = ctx.typeAssigner.assignType(untpdCtr, moduleClassSym.primaryConstructor) | ||
|
||
val parents = List(TypeTree(defn.ObjectClass.typeRef)) | ||
val clsDef = | ||
tpd.ClassDefWithParents(moduleClassSym.asClass, ctr, parents, body) | ||
.withSpan(moduleClassSym.span) | ||
|
||
val newCls = | ||
Apply(New(ref(moduleClassSym)).select(moduleClassSym.primaryConstructor), Nil) | ||
val modVal = | ||
ValDef(moduleClassSym.companionModule.asTerm, newCls).withSpan(clsDef.span) | ||
.withSpan(moduleClassSym.companionModule.span) | ||
List(modVal, clsDef) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import scala.quoted.* | ||
|
||
class Macro: | ||
inline def foo = ${ Macro.fooImpl } | ||
|
||
object Macro: | ||
private def fooImpl(using Quotes) = '{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
def test = | ||
new Macro().foo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import scala.quoted.* | ||
|
||
inline def foo = ${ fooImpl } | ||
|
||
private def fooImpl(using Quotes) = '{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
def test = foo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import scala.quoted.* | ||
|
||
class Macro: | ||
inline def foo = ${ Macro.fooImpl } | ||
|
||
object Macro: | ||
private def fooImpl(using Quotes) = '{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
def test = | ||
new Macro().foo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import scala.quoted.* | ||
|
||
inline def foo = ${ fooImpl } | ||
|
||
private def fooImpl(using Quotes) = '{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
def test = foo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package foo | ||
|
||
trait Bar: | ||
inline def baz = Baz | ||
|
||
private[foo] object Baz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package foo | ||
|
||
trait Bar: | ||
inline def baz = Baz | ||
|
||
private[foo] object Baz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// We first compile A using 3.1 to generate the old accessors | ||
// Then we compile this file to link against the old accessors | ||
// Finally we recompile A using the current compiler to generate a version | ||
// of A that contains the new accessors (and the old for backwards compat) | ||
|
||
@main def Test = | ||
val bar: foo.Bar = new foo.Bar{} | ||
bar.baz // test that old accessor links in 3.4+ | ||
|
||
// Check that both accessors exist in the bytecode | ||
val barMethods = | ||
java.lang.Class.forName("foo.Bar").getMethods() | ||
.filter(_.getName().contains("inline")) | ||
.filter(x => (x.getModifiers() & java.lang.reflect.Modifier.STATIC) == 0) | ||
.map(_.getName()) | ||
val barObjectMethods = | ||
java.lang.Class.forName("foo.Bar$inline$accessors").getMethods() | ||
.filter(_.getName().contains("inline")) | ||
.map(_.getName()) | ||
|
||
println("3.0-3.3 inline accessor: " + barMethods.toList) | ||
println("3.4+ inline accessor: " + barObjectMethods.toList) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
3.0-3.3 inline accessor: List(Macro$$inline$fooImpl) | ||
3.4+ inline accessor: List(inline$fooImpl) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import scala.quoted.* | ||
|
||
class Macro: | ||
inline def foo = /*${*/ Macro.fooImpl /*}*/ | ||
|
||
object Macro: | ||
private def fooImpl/*(using Quotes)*/ = {} |
Oops, something went wrong.