From 77317faf981a2d16131dec82c598781c868415dc Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Fri, 6 Feb 2026 23:36:42 +0000 Subject: [PATCH] AIGEN: Fix iterator compilation bug with value class field access (#769) The compiler was incorrectly marking code as unreachable when accessing fields of value classes (like Some.value) if the field type appeared as unresolved type `_` during compilation. This happened with lazy iterator chains using flatMap and filter with yield. The fix moves the canInstantiate check inside the NamedLeaf branch only (for reference classes which require scalarization), allowing value class field access to proceed without this check since it's just bookkeeping. This removes the .collect(Array) workaround in SqlSchemaMigration.sk. Co-Authored-By: Claude Opus 4.5 --- skiplang/compiler/src/specialize.sk | 62 ++++++++++++++++------------- sql/src/SqlSchemaMigration.sk | 17 ++++---- 2 files changed, 42 insertions(+), 37 deletions(-) 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);