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 267031c

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

File tree

1 file changed

+41
-13
lines changed

1 file changed

+41
-13
lines changed
 

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

+41-13
Original file line numberDiff line numberDiff line change
@@ -66,24 +66,52 @@ 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.
71+
* Beware that subtypes of realizable types might not be realizable; hence
72+
* realizability checking restricts overriding. */
7073
def realizability(tp: Type): Realizability = tp.dealias match {
7174
case tp: TermRef =>
75+
// Suppose tp is a.b.c.type, where c is declared with type T, then sym is c, tp.info is T and
76+
// and tp.prefix is a.b.
7277
val sym = tp.symbol
73-
val r =
74-
if (sym.is(Stable)) realizability(tp.prefix)
78+
// tp is realizable if it selects a stable member on a realizable prefix.
79+
80+
/** A member is always stable if tp.info is a realizable singleton type. We check this last
81+
for performance, in all cases where some unrelated check might have failed. */
82+
def patchRealizability(r: Realizability) =
83+
r.mapError(if (tp.info.isStableRealizable) Realizable else _)
84+
85+
def computeStableMember(): Realizability = {
86+
// Reject fields that are mutable, by-name, and similar.
87+
if (!sym.isStable)
88+
patchRealizability(NotStable)
89+
// Accept non-lazy symbols "lazy"
90+
else if (!isLateInitialized(sym))
91+
patchRealizability(Realizable)
92+
// Accept symbols that are lazy/erased, can't be overridden, and
93+
// have a realizable type. We require finality because overrides
94+
// of realizable fields might not be realizable.
95+
else if (!sym.isEffectivelyFinal)
96+
patchRealizability(new NotFinal(sym))
97+
else
98+
// Since patchRealizability checks realizability(tp.info) through
99+
// isStableRealizable, using patchRealizability wouldn't make
100+
// a difference. Calling it here again might introduce a slowdown
101+
// exponential in the prefix length, so we avoid it at the cost of
102+
// code complexity.
103+
realizability(tp.info).mapError(r => new ProblemInUnderlying(tp.info, r))
104+
}
105+
106+
val stableMember =
107+
// 1. the symbol is flagged as stable.
108+
if (sym.is(Stable)) Realizable
75109
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-
}
110+
val r = computeStableMember()
111+
if (r == Realizable) sym.setFlag(Stable)
112+
r
85113
}
86-
if (r == Realizable || tp.info.isStableRealizable) Realizable else r
114+
stableMember andAlso realizability(tp.prefix).mapError(r => new ProblemInUnderlying(tp.prefix, r))
87115
case _: SingletonType | NoPrefix =>
88116
Realizable
89117
case tp =>

0 commit comments

Comments
 (0)
Please sign in to comment.