@@ -68,7 +68,9 @@ class CheckRealizable(implicit ctx: Context) {
6868 */
6969 private def isLateInitialized (sym : Symbol ) = sym.is(Lazy , butNot = Module )
7070
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. */
7274 def realizability (tp : Type ): Realizability = tp.dealias match {
7375 case tp : TermRef =>
7476 // 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) {
8385 def patchRealizability (r : Realizability ) =
8486 r.mapError(if (tp.info.isStableRealizable) Realizable else _)
8587 val r =
88+ // Reject fields that are mutable, by-name, and similar.
8689 if (! sym.isStable)
8790 patchRealizability(NotStable )
8891 // 3. If the symbol isn't "lazy" and its prefix is realizable
@@ -91,10 +94,13 @@ class CheckRealizable(implicit ctx: Context) {
9194 // stable if it appears under a realizable prefix.
9295 // XXX: Add object DependsOnPrefix extends Realizability(""), but filter it out here.
9396 patchRealizability(realizability(tp.prefix))
94- // 4. If the symbol can't be overridden, and
9597 else if (! sym.isEffectivelyFinal)
9698 patchRealizability(new NotFinal (sym))
9799 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+
98104 // Since patchRealizability checks realizability(tp.info) through
99105 // isStableRealizable, using patchRealizability wouldn't make
100106 // a difference, and calling it here again might introduce
0 commit comments