Skip to content

Commit 5affe4e

Browse files
Merge remote-tracking branch 'origin/main' into fix-issue-9049
2 parents bdf261b + 16452b6 commit 5affe4e

3 files changed

Lines changed: 63 additions & 10 deletions

File tree

src/cli/test/fx_test_specs.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,11 @@ pub const io_spec_tests = [_]TestSpec{
273273
.io_spec = "1>done",
274274
.description = "Regression test: Minimal repro for issue #8897 panic",
275275
},
276+
.{
277+
.roc_file = "test/fx/issue8898.roc",
278+
.io_spec = "1>done",
279+
.description = "Regression test: Polymorphic function with for loop list literal panic (issue #8898)",
280+
},
276281
.{
277282
.roc_file = "test/fx/static_dispatch_platform_module.roc",
278283
.io_spec = "1>Result: start-middle-end",

src/eval/interpreter.zig

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11907,17 +11907,41 @@ pub const Interpreter = struct {
1190711907
}
1190811908
try value_stack.push(dest);
1190911909
} else {
11910-
// Get element type from list_rt_var. The list type should be List(elem)
11911-
// where vars[0] is backing and vars[1] is the element type.
11912-
// The element type may be flex (e.g., Num *) which is fine - downstream
11913-
// code like getRuntimeLayout will default flex to Dec as needed.
11910+
// Determine the element type for this non-empty list literal.
11911+
//
11912+
// Primary path: Extract from list type structure.
11913+
// The list type should be List(elem) where vars[0] is backing and
11914+
// vars[1] is the element type. The element type may be flex (e.g.,
11915+
// Num *) which is fine - downstream code like getRuntimeLayout will
11916+
// default flex to Dec as needed.
11917+
//
11918+
// Alternative path: Derive from first element's type.
11919+
// In polymorphic contexts (e.g., inside a for loop in a polymorphic
11920+
// function), the list type variable may resolve to a flex/rigid
11921+
// rather than a List(elem) structure. This happens due to union-find
11922+
// redirect chains in the type store. In this case, we determine the
11923+
// element type from the first element's compile-time type.
11924+
//
11925+
// This alternative is semantically correct because the element type
11926+
// of a list literal [e1, e2, ...] IS the type of its elements - the
11927+
// type checker explicitly unifies the list's element type with the
11928+
// first element's type (see Check.zig e_list handling).
1191411929
const list_resolved = self.runtime_types.resolveVar(list_rt_var);
11915-
std.debug.assert(list_resolved.desc.content == .structure);
11916-
std.debug.assert(list_resolved.desc.content.structure == .nominal_type);
11917-
const nom = list_resolved.desc.content.structure.nominal_type;
11918-
const vars = self.runtime_types.sliceVars(nom.vars.nonempty);
11919-
std.debug.assert(vars.len == 2); // vars[0] = backing, vars[1] = element type
11920-
const elem_rt_var = vars[1];
11930+
const elem_rt_var = blk: {
11931+
if (list_resolved.desc.content == .structure) {
11932+
if (list_resolved.desc.content.structure == .nominal_type) {
11933+
const nom = list_resolved.desc.content.structure.nominal_type;
11934+
const vars = self.runtime_types.sliceVars(nom.vars.nonempty);
11935+
if (vars.len == 2) {
11936+
// vars[0] = backing, vars[1] = element type
11937+
break :blk vars[1];
11938+
}
11939+
}
11940+
}
11941+
// List type is flex/rigid - derive element type from first element
11942+
const first_elem_ct_var = can.ModuleEnv.varFrom(elems[0]);
11943+
break :blk try self.translateTypeVar(self.env, first_elem_ct_var);
11944+
};
1192111945

1192211946
const elem_resolved = self.runtime_types.resolveVar(elem_rt_var);
1192311947
const elem_content = elem_resolved.desc.content;

test/fx/issue8898.roc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
app [main!] { pf: platform "./platform/main.roc" }
2+
3+
import pf.Stdout
4+
5+
# Issue 8898: Panic when running test on polymorphic function with for loop
6+
# "thread panic: reached unreachable code" at interpreter.zig
7+
# because the interpreter expects list type to be a concrete structure,
8+
# but with polymorphic list parameters in a for loop context,
9+
# the compile-time type is a flex variable instead.
10+
11+
rev : List(a) -> List(a)
12+
rev = |l| {
13+
var $acc = []
14+
for e in l {
15+
$acc = List.concat([e], $acc)
16+
}
17+
$acc
18+
}
19+
20+
expect rev(["a", "b", "c"]) == ["c", "b", "a"]
21+
22+
main! = || {
23+
Stdout.line!("done")
24+
}

0 commit comments

Comments
 (0)