Skip to content

Commit 3acdd84

Browse files
mbouazizclaude
andcommitted
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<T>.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 <[email protected]>
1 parent 804939e commit 3acdd84

2 files changed

Lines changed: 42 additions & 37 deletions

File tree

skiplang/compiler/src/specialize.sk

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3156,32 +3156,41 @@ mutable class FunSpecializer{
31563156
typ: Type,
31573157
pos: Pos,
31583158
): void {
3159-
val = (this.canInstantiate(typ), this.getValue(context, gf.obj)) match {
3160-
| (_, NotExists(why)) -> this.unreachable(pos, why)
3161-
| (false, _) ->
3162-
this.unreachable(
3163-
pos,
3164-
`Attempt to read field ${gf.obj.getType()}.${gf.field} of ` +
3165-
`type ${typ} that cannot be instantiated`,
3166-
)
3167-
| (true, Exists(obj @ NamedLeaf _)) ->
3168-
// Loading from a normal reference class.
3169-
shape = this.scalarize(typ);
3170-
Exists(
3171-
shape.map(
3172-
(name, ftype) -> {
3173-
this.emitGetField{
3174-
typ => ftype,
3175-
pos,
3176-
field => name,
3177-
obj => obj.value,
3178-
prettyName => gf.prettyName,
3179-
}.id
3180-
},
3181-
gf.field,
3182-
),
3183-
)
3184-
| (true, Exists(cv @ NamedInner _)) ->
3159+
val = this.getValue(context, gf.obj) match {
3160+
| NotExists(why) -> this.unreachable(pos, why)
3161+
| Exists(obj @ NamedLeaf _) ->
3162+
// Loading from a normal reference class requires scalarizing the type,
3163+
// which requires the type to be instantiable.
3164+
if (!this.canInstantiate(typ)) {
3165+
this.unreachable(
3166+
pos,
3167+
`Attempt to read field ${gf.obj.getType()}.${gf.field} of ` +
3168+
`type ${typ} that cannot be instantiated`,
3169+
)
3170+
} else {
3171+
shape = this.scalarize(typ);
3172+
Exists(
3173+
shape.map(
3174+
(name, ftype) -> {
3175+
this.emitGetField{
3176+
typ => ftype,
3177+
pos,
3178+
field => name,
3179+
obj => obj.value,
3180+
prettyName => gf.prettyName,
3181+
}.id
3182+
},
3183+
gf.field,
3184+
),
3185+
)
3186+
}
3187+
| Exists(cv @ NamedInner _) ->
3188+
// Loading from a value class generates no code, just bookkeeping.
3189+
// Note: We don't check canInstantiate(typ) here because value class
3190+
// field access doesn't require scalarizing the type - it's just
3191+
// bookkeeping. This allows accessing fields like Some<T>.value where
3192+
// T might appear as unresolved type _ during compilation.
3193+
// See issue #769 for the iterator compilation bug this fixes.
31853194
if (
31863195
gf.field == "value" &&
31873196
this.getOptionStyle(context, gf.obj.getType()).isSome()
@@ -3191,7 +3200,6 @@ mutable class FunSpecializer{
31913200
!cv = cv.getField("valueIfSome", pos).asInner(pos)
31923201
};
31933202

3194-
// Loading from a value class generates no code, just bookkeeping.
31953203
Exists(cv.getField(gf.field, pos))
31963204
};
31973205

sql/src/SqlSchemaMigration.sk

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,14 @@ private fun resetReactiveViews(
1616
options: Options,
1717
): void {
1818
viewsDir = context.unsafeGetEagerDir(getViewsDir(context).dirName);
19-
viewsToReset = viewsDir
20-
.unsafeGetFileIter()
21-
.flatMap((key_fileiter) -> {
22-
(_key, fileiter) = key_fileiter;
23-
fileiter.filter((file) ->
24-
SelectFile::type(file).cselect.from.any((from) ->
25-
alteredDirs.contains(from.i0.name)
26-
)
19+
viewsToReset = viewsDir.unsafeGetFileIter().flatMap((key_fileiter) -> {
20+
(_key, fileiter) = key_fileiter;
21+
fileiter.filter((file) ->
22+
SelectFile::type(file).cselect.from.any((from) ->
23+
alteredDirs.contains(from.i0.name)
2724
)
28-
})
29-
.collect(Array); // TODO #769: removing this collect leads to a runtime error
25+
)
26+
});
3027

3128
for (childView in viewsToReset) {
3229
selectFile = SelectFile::type(childView);

0 commit comments

Comments
 (0)