Skip to content

Commit ed51433

Browse files
committed
Refactor realizability to also cache result of isStableRealizable
1 parent d1e5d40 commit ed51433

File tree

1 file changed

+32
-13
lines changed

1 file changed

+32
-13
lines changed

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

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,22 +70,41 @@ class CheckRealizable(implicit ctx: Context) {
7070
*/
7171
private def isLateInitialized(sym: Symbol) = sym.is(LateInitialized, butNot = Module)
7272

73-
/** The realizability status of given type `tp`*/
73+
/** The realizability status of given type `tp` */
7474
def realizability(tp: Type): Realizability = tp.dealias match {
7575
case tp: TermRef =>
76+
// Suppose tp is a.b.c.type, where c is declared with type T, then sym is c, tp.info is T and
77+
// and tp.prefix is a.b.
7678
val sym = tp.symbol
77-
val r =
78-
if (sym.is(Stable)) realizability(tp.prefix)
79-
else {
80-
val r =
81-
if (!sym.isStable) NotStable
82-
else if (!isLateInitialized(sym)) realizability(tp.prefix)
83-
else if (!sym.isEffectivelyFinal) new NotFinal(sym)
84-
else realizability(tp.info).mapError(r => new ProblemInUnderlying(tp.info, r))
85-
if (r == Realizable) sym.setFlag(Stable)
86-
r
87-
}
88-
if (r == Realizable || tp.info.isStableRealizable) Realizable else r
79+
// We know tp is realizable if either:
80+
// 1. the symbol is stable and the prefix is realizable (so that, say, it contains no vars):
81+
if (sym.is(Stable)) realizability(tp.prefix)
82+
else {
83+
// 2. if tp.info is a realizable singleton type. We check this last
84+
// for performance, in all cases where some unrelated check might have failed.
85+
def patchRealizability(r: Realizability) =
86+
r.mapError(if (tp.info.isStableRealizable) Realizable else _)
87+
val r =
88+
if (!sym.isStable)
89+
patchRealizability(NotStable)
90+
// 3. If the symbol isn't "lazy" and its prefix is realizable
91+
else if (!isLateInitialized(sym))
92+
// XXX: This is a bit fishy: we only cache that the symbol is
93+
// stable if it appears under a realizable prefix.
94+
// XXX: Add object DependsOnPrefix extends Realizability(""), but filter it out here.
95+
patchRealizability(realizability(tp.prefix))
96+
// 4. If the symbol can't be overridden, and
97+
else if (!sym.isEffectivelyFinal)
98+
patchRealizability(new NotFinal(sym))
99+
else
100+
// Since patchRealizability checks realizability(tp.info) through
101+
// isStableRealizable, using patchRealizability wouldn't make
102+
// a difference, and calling it here again might introduce
103+
// a slowdown exponential in the prefix length.
104+
realizability(tp.info).mapError(r => new ProblemInUnderlying(tp.info, r))
105+
if (r == Realizable) sym.setFlag(Stable)
106+
r
107+
}
89108
case _: SingletonType | NoPrefix =>
90109
Realizable
91110
case tp =>

0 commit comments

Comments
 (0)