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