diff --git a/skiplang/compiler/src/specialize.sk b/skiplang/compiler/src/specialize.sk index 237708368..f344c5a43 100644 --- a/skiplang/compiler/src/specialize.sk +++ b/skiplang/compiler/src/specialize.sk @@ -3156,32 +3156,41 @@ mutable class FunSpecializer{ typ: Type, pos: Pos, ): void { - val = (this.canInstantiate(typ), this.getValue(context, gf.obj)) match { - | (_, NotExists(why)) -> this.unreachable(pos, why) - | (false, _) -> - this.unreachable( - pos, - `Attempt to read field ${gf.obj.getType()}.${gf.field} of ` + - `type ${typ} that cannot be instantiated`, - ) - | (true, Exists(obj @ NamedLeaf _)) -> - // Loading from a normal reference class. - shape = this.scalarize(typ); - Exists( - shape.map( - (name, ftype) -> { - this.emitGetField{ - typ => ftype, - pos, - field => name, - obj => obj.value, - prettyName => gf.prettyName, - }.id - }, - gf.field, - ), - ) - | (true, Exists(cv @ NamedInner _)) -> + val = this.getValue(context, gf.obj) match { + | NotExists(why) -> this.unreachable(pos, why) + | Exists(obj @ NamedLeaf _) -> + // Loading from a normal reference class requires scalarizing the type, + // which requires the type to be instantiable. + if (!this.canInstantiate(typ)) { + this.unreachable( + pos, + `Attempt to read field ${gf.obj.getType()}.${gf.field} of ` + + `type ${typ} that cannot be instantiated`, + ) + } else { + shape = this.scalarize(typ); + Exists( + shape.map( + (name, ftype) -> { + this.emitGetField{ + typ => ftype, + pos, + field => name, + obj => obj.value, + prettyName => gf.prettyName, + }.id + }, + gf.field, + ), + ) + } + | Exists(cv @ NamedInner _) -> + // Loading from a value class generates no code, just bookkeeping. + // Note: We don't check canInstantiate(typ) here because value class + // field access doesn't require scalarizing the type - it's just + // bookkeeping. This allows accessing fields like Some.value where + // T might appear as unresolved type _ during compilation. + // See issue #769 for the iterator compilation bug this fixes. if ( gf.field == "value" && this.getOptionStyle(context, gf.obj.getType()).isSome() @@ -3191,7 +3200,6 @@ mutable class FunSpecializer{ !cv = cv.getField("valueIfSome", pos).asInner(pos) }; - // Loading from a value class generates no code, just bookkeeping. Exists(cv.getField(gf.field, pos)) }; diff --git a/sql/src/SqlSchemaMigration.sk b/sql/src/SqlSchemaMigration.sk index 2efefa6c7..fe1bced5e 100644 --- a/sql/src/SqlSchemaMigration.sk +++ b/sql/src/SqlSchemaMigration.sk @@ -16,17 +16,14 @@ private fun resetReactiveViews( options: Options, ): void { viewsDir = context.unsafeGetEagerDir(getViewsDir(context).dirName); - viewsToReset = viewsDir - .unsafeGetFileIter() - .flatMap((key_fileiter) -> { - (_key, fileiter) = key_fileiter; - fileiter.filter((file) -> - SelectFile::type(file).cselect.from.any((from) -> - alteredDirs.contains(from.i0.name) - ) + viewsToReset = viewsDir.unsafeGetFileIter().flatMap((key_fileiter) -> { + (_key, fileiter) = key_fileiter; + fileiter.filter((file) -> + SelectFile::type(file).cselect.from.any((from) -> + alteredDirs.contains(from.i0.name) ) - }) - .collect(Array); // TODO #769: removing this collect leads to a runtime error + ) + }); for (childView in viewsToReset) { selectFile = SelectFile::type(childView);