@@ -68,7 +68,9 @@ class CheckRealizable(implicit ctx: Context) {
68
68
*/
69
69
private def isLateInitialized (sym : Symbol ) = sym.is(Lazy , butNot = Module )
70
70
71
- /** The realizability status of given type `tp` */
71
+ /** The realizability status of given type `tp`. We can only select members from realizable types.
72
+ * A type is realizable if it has non-null values. However, realizable types can
73
+ * have non-realizable subtypes, so we must restrict overriding. */
72
74
def realizability (tp : Type ): Realizability = tp.dealias match {
73
75
case tp : TermRef =>
74
76
// Suppose tp is a.b.c.type, where c is declared with type T, then sym is c, tp.info is T and
@@ -83,6 +85,7 @@ class CheckRealizable(implicit ctx: Context) {
83
85
def patchRealizability (r : Realizability ) =
84
86
r.mapError(if (tp.info.isStableRealizable) Realizable else _)
85
87
val r =
88
+ // Reject fields that are mutable, by-name, and similar.
86
89
if (! sym.isStable)
87
90
patchRealizability(NotStable )
88
91
// 3. If the symbol isn't "lazy" and its prefix is realizable
@@ -91,10 +94,13 @@ class CheckRealizable(implicit ctx: Context) {
91
94
// stable if it appears under a realizable prefix.
92
95
// XXX: Add object DependsOnPrefix extends Realizability(""), but filter it out here.
93
96
patchRealizability(realizability(tp.prefix))
94
- // 4. If the symbol can't be overridden, and
95
97
else if (! sym.isEffectivelyFinal)
96
98
patchRealizability(new NotFinal (sym))
97
99
else
100
+ // 4. If the symbol is effectively final, and a lazy or erased val
101
+ // and has a realizable type. We require finality because overrides
102
+ // of realizable fields might not be realizable.
103
+
98
104
// Since patchRealizability checks realizability(tp.info) through
99
105
// isStableRealizable, using patchRealizability wouldn't make
100
106
// a difference, and calling it here again might introduce
0 commit comments