The bug is already covered by the faster eval test in eval_test.zig.
The fx platform test is not needed since the bug is purely in the
interpreter's for loop element type handling.
When HTTP fetch or flush failed, the code explicitly closed the file
and deleted it before returning an error. But returning an error also
triggered the errdefer block which tried to close the file again,
causing a crash on Windows where CloseHandle asserts success.
The fix removes the explicit close/delete calls in error paths since
the errdefer already handles cleanup. The errdefer pattern is the
correct way to handle this - it ensures cleanup happens exactly once
whether we return normally or with an error.
When an HTTP fetch fails, downloadToFile explicitly closes the file
before returning an error. The error return then triggers the errdefer
block which tries to close the file again, causing a crash.
This test uses an unreachable URL (localhost port 1) to trigger the
HTTP error path and reproduce the double-close bug.
The bug only occurs with unsuffixed number literals (which default to
Dec), not with suffixed ones like 8i64. Update the fx test to use
unsuffixed numbers to properly reproduce the bug, and add a faster
eval test that verifies the same behavior.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a for loop iterates over a list passed to a function with no type
annotation, the pattern's compile-time type variable was a flex
variable. This translated to a runtime flex type, which caused
InvalidMethodReceiver when trying to call methods like .to_str() on the
loop elements.
The fix extracts the element type from the list's actual runtime type
(e.g., List(I64)) instead of using the pattern's translated type. This
ensures method resolution has the concrete nominal type information it
needs.
Fixes#8664
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The fix is an interpreter change, so eval_test.zig tests are sufficient.
Removed the fx platform test file and spec.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move the regression test from a CLI test to a type-checker unit test
since it only tests type checking behavior.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Issue #8650: List.append wasn't properly incrementing refcounts for strings
inside tuples. The root cause was that isRefcounted() returns false for
tuples (they aren't directly heap-allocated), but tuples can transitively
contain refcounted data like strings.
Added layoutContainsRefcounted() helper function that checks if a layout
transitively contains any refcounted data (strings, lists, boxes), including
nested tuples, records, and tag unions. This is used in list_append to
determine when element incref/decref callbacks are needed.
Note: This fix is for the interpreter path. The compiled code path (LLVM)
would need a similar fix in the Rust codegen, but that is out of scope
for this change.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The interpreter was unconditionally defaulting flex/rigid type variables
to Dec for all dot access expressions. This broke record field access
when the record type wasn't fully resolved at compile time, because
records are not Dec.
The fix distinguishes between method calls (args != null) and field
access (args == null). Only method calls with flex/rigid receivers
default to Dec, since numeric literals like `(-3.14).abs()` need this
for proper type resolution. Field access passes null for expected_rt_var
to let the receiver determine its own type.
Additionally, in dot_access_resolve, field names must be translated
from the CIR's identifier store to the runtime layout store's identifier
store, since these can differ between modules.
Fixes#8647🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a variable added to var_pool at rank 1 was later redirected (via
setVarRedirect) to a variable at rank 2, generalization would try to
add the resolved variable at rank 2 to tmp_var_pool which only goes up
to rank 1, causing a panic.
The fix caps the effective rank at rank_to_generalize when copying
variables to tmp_var_pool. This allows the rank adjustment phase to
properly handle these variables.
Fixes#8656🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
When handling low-level lambdas (like Str.is_eq), the code was decrefing
arguments with borrow semantics, but the defer statements at the top of
these functions already handle decrefing. This caused a double-free when
comparing heap-allocated strings (24+ characters).
The fix removes the explicit decrefs in the low-level lambda paths since
the defer statements already handle cleanup.
Resolved conflict in fx_test_specs.zig by including both:
- list_append_stdin_uaf.roc test from main
- list_first_method.roc and list_first_function.roc regression tests from this branch
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>