Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 72ea704

Browse files
committedDec 2, 2018
Refactor realizability to also cache result of isStableRealizable
Also streamline logic significantly.
1 parent 6d063a4 commit 72ea704

File tree

1 file changed

+42
-13
lines changed

1 file changed

+42
-13
lines changed
 

Diff for: ‎compiler/src/dotty/tools/dotc/core/CheckRealizable.scala

+42-13
Original file line numberDiff line numberDiff line change
@@ -66,24 +66,53 @@ class CheckRealizable(implicit ctx: Context) {
6666
*/
6767
private def isLateInitialized(sym: Symbol) = sym.is(LateInitialized, butNot = Module)
6868

69-
/** The realizability status of given type `tp`*/
69+
/** The realizability status of given type `tp`. Types can only project
70+
* members from realizable types, that is, types having non-null values and
71+
* not depending on mutable state.
72+
* Beware that subtypes of realizable types might not be realizable; hence
73+
* realizability checking restricts overriding. */
7074
def realizability(tp: Type): Realizability = tp.dealias match {
7175
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.
7278
val sym = tp.symbol
73-
val r =
74-
if (sym.is(Stable)) realizability(tp.prefix)
79+
// tp is realizable if it selects a stable member on a realizable prefix.
80+
81+
/** A member is always stable if tp.info is a realizable singleton type. We check this last
82+
for performance, in all cases where some unrelated check might have failed. */
83+
def patchRealizability(r: Realizability) =
84+
r.mapError(if (tp.info.isStableRealizable) Realizable else _)
85+
86+
def computeStableMember(): Realizability = {
87+
// Reject fields that are mutable, by-name, and similar.
88+
if (!sym.isStable)
89+
patchRealizability(NotStable)
90+
// Accept non-lazy symbols "lazy"
91+
else if (!isLateInitialized(sym))
92+
patchRealizability(Realizable)
93+
// Accept symbols that are lazy/erased, can't be overridden, and
94+
// have a realizable type. We require finality because overrides
95+
// of realizable fields might not be realizable.
96+
else if (!sym.isEffectivelyFinal)
97+
patchRealizability(new NotFinal(sym))
98+
else
99+
// Since patchRealizability checks realizability(tp.info) through
100+
// isStableRealizable, using patchRealizability wouldn't make
101+
// a difference. Calling it here again might introduce a slowdown
102+
// exponential in the prefix length, so we avoid it at the cost of
103+
// code complexity.
104+
realizability(tp.info).mapError(r => new ProblemInUnderlying(tp.info, r))
105+
}
106+
107+
val stableMember =
108+
// 1. the symbol is flagged as stable.
109+
if (sym.is(Stable)) Realizable
75110
else {
76-
val r =
77-
if (!sym.isStable) NotStable
78-
else if (!isLateInitialized(sym)) Realizable
79-
else if (!sym.isEffectivelyFinal) new NotFinal(sym)
80-
else realizability(tp.info).mapError(r => new ProblemInUnderlying(tp.info, r))
81-
r andAlso {
82-
sym.setFlag(Stable)
83-
realizability(tp.prefix).mapError(r => new ProblemInUnderlying(tp.prefix, r))
84-
}
111+
val r = computeStableMember()
112+
if (r == Realizable) sym.setFlag(Stable)
113+
r
85114
}
86-
if (r == Realizable || tp.info.isStableRealizable) Realizable else r
115+
stableMember andAlso realizability(tp.prefix).mapError(r => new ProblemInUnderlying(tp.prefix, r))
87116
case _: SingletonType | NoPrefix =>
88117
Realizable
89118
case tp =>

0 commit comments

Comments
 (0)
Please sign in to comment.