@@ -70,22 +70,41 @@ class CheckRealizable(implicit ctx: Context) {
70
70
*/
71
71
private def isLateInitialized (sym : Symbol ) = sym.is(LateInitialized , butNot = Module )
72
72
73
- /** The realizability status of given type `tp`*/
73
+ /** The realizability status of given type `tp` */
74
74
def realizability (tp : Type ): Realizability = tp.dealias match {
75
75
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.
76
78
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
+ }
89
108
case _ : SingletonType | NoPrefix =>
90
109
Realizable
91
110
case tp =>
0 commit comments