Skip to content

Commit 16bf86f

Browse files
authored
Merge pull request #11330 from dotty-staging/reuseSymDenotations
Make it possible to always set the prefix of denotations
2 parents a63b1d1 + 4cbe9c8 commit 16bf86f

File tree

6 files changed

+38
-24
lines changed

6 files changed

+38
-24
lines changed

compiler/src/dotty/tools/dotc/config/Config.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,13 @@ object Config {
205205

206206
/** When in IDE, turn StaleSymbol errors into warnings instead of crashing */
207207
inline val ignoreStaleInIDE = true
208+
209+
/** If true, `Denotation#asSeenFrom` is allowed to return an existing
210+
* `SymDenotation` instead of allocating a new `SingleDenotation` if
211+
* the two would only differ in their `prefix` (SymDenotation always
212+
* have `NoPrefix` as their prefix).
213+
* This is done for performance reasons: when compiling Dotty itself this
214+
* reduces the number of allocated denotations by ~50%.
215+
*/
216+
inline val reuseSymDenotations = true
208217
}

compiler/src/dotty/tools/dotc/config/JavaPlatform.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class JavaPlatform extends Platform {
2121
}
2222

2323
// The given symbol is a method with the right name and signature to be a runnable java program.
24-
def isMainMethod(sym: SymDenotation)(using Context): Boolean =
24+
def isMainMethod(sym: Symbol)(using Context): Boolean =
2525
(sym.name == nme.main) && (sym.info match {
2626
case MethodTpe(_, defn.ArrayOf(el) :: Nil, restpe) => el =:= defn.StringType && (restpe isRef defn.UnitClass)
2727
case _ => false

compiler/src/dotty/tools/dotc/config/Platform.scala

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,10 @@ abstract class Platform {
3838
def newClassLoader(bin: AbstractFile)(using Context): SymbolLoader
3939

4040
/** The given symbol is a method with the right name and signature to be a runnable program. */
41-
def isMainMethod(sym: SymDenotation)(using Context): Boolean
41+
def isMainMethod(sym: Symbol)(using Context): Boolean
4242

4343
/** The given class has a main method. */
4444
final def hasMainMethod(sym: Symbol)(using Context): Boolean =
45-
sym.info.member(nme.main).hasAltWith {
46-
case x: SymDenotation => isMainMethod(x) && (sym.is(Module) || x.isStatic)
47-
case _ => false
48-
}
45+
sym.info.member(nme.main).hasAltWith(d =>
46+
isMainMethod(d.symbol) && (sym.is(Module) || d.symbol.isStatic))
4947
}

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -573,8 +573,12 @@ object Denotations {
573573

574574
final def name(using Context): Name = symbol.name
575575

576-
/** If this is not a SymDenotation: The prefix under which the denotation was constructed.
577-
* NoPrefix for SymDenotations.
576+
/** For SymDenotation, this is NoPrefix. For other denotations this is the prefix
577+
* under which the denotation was constructed.
578+
*
579+
* Note that `asSeenFrom` might return a `SymDenotation` and therefore in
580+
* general one cannot rely on `prefix` being set, see
581+
* `Config.reuseSymDenotations` for details.
578582
*/
579583
def prefix: Type = NoPrefix
580584

@@ -1044,24 +1048,25 @@ object Denotations {
10441048
}
10451049

10461050
/** The derived denotation with the given `info` transformed with `asSeenFrom`.
1047-
* The prefix of the derived denotation is the new prefix `pre` if the type is
1048-
* opaque, or if the current prefix is already different from `NoPrefix`.
1049-
* That leaves SymDenotations (which have NoPrefix as the prefix), which are left
1050-
* as SymDenotations unless the type is opaque. The treatment of opaque types
1051-
* is needed, without it i7159.scala fails in from-tasty. Without the treatment,
1052-
* opaque type denotations in subclasses are kept as SymDenotations, which means
1053-
* that the transform in `ElimOpaque` will return the symbol's opaque alias without
1054-
* adding the needed asSeenFrom.
10551051
*
1056-
* Logically, the right thing to do would be to extend the same treatment to all denotations
1057-
* Currently this fails the bootstrap. There's also a concern that this generalization
1058-
* would create more denotation objects, at a price in performance.
1052+
* As a performance hack, we might reuse an existing SymDenotation,
1053+
* instead of creating a new denotation with a given `prefix`,
1054+
* see `Config.reuseSymDenotations`.
10591055
*/
10601056
def derived(info: Type) =
1061-
derivedSingleDenotation(
1062-
symbol,
1063-
info.asSeenFrom(pre, owner),
1064-
if (symbol.is(Opaque) || this.prefix != NoPrefix) pre else this.prefix)
1057+
/** Do we need to return a denotation with a prefix set? */
1058+
def needsPrefix =
1059+
// For opaque types, the prefix is used in `ElimOpaques#transform`,
1060+
// without this i7159.scala would fail when compiled from tasty.
1061+
symbol.is(Opaque)
1062+
1063+
val derivedInfo = info.asSeenFrom(pre, owner)
1064+
if Config.reuseSymDenotations && this.isInstanceOf[SymDenotation]
1065+
&& (derivedInfo eq info) && !needsPrefix then
1066+
this
1067+
else
1068+
derivedSingleDenotation(symbol, derivedInfo, pre)
1069+
end derived
10651070

10661071
// Tt could happen that we see the symbol with prefix `this` as a member a different class
10671072
// through a self type and that it then has a different info. In this case we have to go

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,8 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisPhase =>
556556
// The Lifter updates the type of symbols using `installAfter` to give them a
557557
// new `SymDenotation`, but that doesn't affect non-sym denotations, so we
558558
// reload them manually here.
559+
// Note: If you tweak this code, make sure to test your changes with
560+
// `Config.reuseSymDenotations` set to false to exercise this path more.
559561
if denot.isInstanceOf[NonSymSingleDenotation] && lifter.free.contains(sym) then
560562
tree.qualifier.select(sym).withSpan(tree.span)
561563
else tree

compiler/src/dotty/tools/dotc/util/Signatures.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ object Signatures {
6666
case _ =>
6767
val funSymbol = fun.symbol
6868
val alternatives = funSymbol.owner.info.member(funSymbol.name).alternatives
69-
val alternativeIndex = alternatives.indexOf(funSymbol.denot) max 0
69+
val alternativeIndex = alternatives.map(_.symbol).indexOf(funSymbol) max 0
7070
(alternativeIndex, alternatives)
7171
}
7272

0 commit comments

Comments
 (0)