mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Merge pull request #8620 from roc-lang/fix-fold-rev
Fix fold_rev static dispatch bug
This commit is contained in:
commit
fee6a37efa
3 changed files with 92 additions and 15 deletions
|
|
@ -1048,3 +1048,23 @@ test "fx platform index out of bounds in instantiate regression" {
|
|||
// Currently it fails with a panic in instantiate.zig.
|
||||
try checkSuccess(run_result);
|
||||
}
|
||||
|
||||
test "fx platform fold_rev static dispatch regression" {
|
||||
// Regression test: Calling fold_rev with static dispatch (method syntax) panics,
|
||||
// but calling it qualified as List.fold_rev(...) works fine.
|
||||
//
|
||||
// The panic occurs with: [1].fold_rev([], |elem, acc| acc.append(elem))
|
||||
// But this works: List.fold_rev([1], [], |elem, acc| acc.append(elem))
|
||||
const allocator = testing.allocator;
|
||||
|
||||
const run_result = try runRoc(allocator, "test/fx/fold_rev_static_dispatch.roc", .{});
|
||||
defer allocator.free(run_result.stdout);
|
||||
defer allocator.free(run_result.stderr);
|
||||
|
||||
try checkSuccess(run_result);
|
||||
|
||||
// Verify the expected output
|
||||
try testing.expect(std.mem.indexOf(u8, run_result.stdout, "Start reverse") != null);
|
||||
try testing.expect(std.mem.indexOf(u8, run_result.stdout, "Reversed: 3 elements") != null);
|
||||
try testing.expect(std.mem.indexOf(u8, run_result.stdout, "Done") != null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15011,22 +15011,63 @@ pub const Interpreter = struct {
|
|||
|
||||
try self.active_closures.append(method_func);
|
||||
|
||||
// Bind receiver first
|
||||
try self.bindings.append(.{
|
||||
.pattern_idx = params[0],
|
||||
.value = receiver_value,
|
||||
.expr_idx = null, // expr_idx not used for method call parameter bindings
|
||||
.source_env = self.env,
|
||||
});
|
||||
// Save the current flex_type_context before adding parameter mappings
|
||||
// This will be restored in call_cleanup (like call_invoke_closure does)
|
||||
var saved_flex_type_context = try self.flex_type_context.clone();
|
||||
errdefer saved_flex_type_context.deinit();
|
||||
|
||||
// Bind explicit arguments
|
||||
// Bind receiver using patternMatchesBind (like call_invoke_closure does)
|
||||
// This creates a copy of the value for the binding
|
||||
const receiver_param_rt_var = try self.translateTypeVar(self.env, can.ModuleEnv.varFrom(params[0]));
|
||||
|
||||
// Propagate flex mappings for receiver (needed for polymorphic type propagation)
|
||||
const receiver_rt_resolved = self.runtime_types.resolveVar(dac.receiver_rt_var);
|
||||
if (receiver_rt_resolved.desc.content == .structure) {
|
||||
const receiver_param_ct_var = can.ModuleEnv.varFrom(params[0]);
|
||||
try self.propagateFlexMappings(self.env, receiver_param_ct_var, dac.receiver_rt_var);
|
||||
}
|
||||
|
||||
if (!try self.patternMatchesBind(params[0], receiver_value, receiver_param_rt_var, roc_ops, &self.bindings, null)) {
|
||||
// Pattern match failed - cleanup and error
|
||||
self.env = saved_env;
|
||||
_ = self.active_closures.pop();
|
||||
method_func.decref(&self.runtime_layout_store, roc_ops);
|
||||
receiver_value.decref(&self.runtime_layout_store, roc_ops);
|
||||
for (arg_values) |arg| arg.decref(&self.runtime_layout_store, roc_ops);
|
||||
if (saved_rigid_subst) |*saved| saved.deinit();
|
||||
self.flex_type_context.deinit();
|
||||
self.flex_type_context = saved_flex_type_context;
|
||||
self.poly_context_generation +%= 1;
|
||||
return error.TypeMismatch;
|
||||
}
|
||||
// Decref the original receiver value since patternMatchesBind made a copy
|
||||
receiver_value.decref(&self.runtime_layout_store, roc_ops);
|
||||
|
||||
// Bind explicit arguments using patternMatchesBind
|
||||
for (arg_values, 0..) |arg, idx| {
|
||||
try self.bindings.append(.{
|
||||
.pattern_idx = params[1 + idx],
|
||||
.value = arg,
|
||||
.expr_idx = null, // expr_idx not used for method call parameter bindings
|
||||
.source_env = self.env,
|
||||
});
|
||||
const param_rt_var = try self.translateTypeVar(self.env, can.ModuleEnv.varFrom(params[1 + idx]));
|
||||
|
||||
// Propagate flex mappings for each argument (needed for polymorphic type propagation)
|
||||
const arg_rt_resolved = self.runtime_types.resolveVar(arg.rt_var);
|
||||
if (arg_rt_resolved.desc.content == .structure) {
|
||||
const param_ct_var = can.ModuleEnv.varFrom(params[1 + idx]);
|
||||
try self.propagateFlexMappings(self.env, param_ct_var, arg.rt_var);
|
||||
}
|
||||
|
||||
if (!try self.patternMatchesBind(params[1 + idx], arg, param_rt_var, roc_ops, &self.bindings, null)) {
|
||||
// Pattern match failed - cleanup and error
|
||||
self.env = saved_env;
|
||||
_ = self.active_closures.pop();
|
||||
method_func.decref(&self.runtime_layout_store, roc_ops);
|
||||
for (arg_values[idx..]) |remaining_arg| remaining_arg.decref(&self.runtime_layout_store, roc_ops);
|
||||
if (saved_rigid_subst) |*saved| saved.deinit();
|
||||
self.flex_type_context.deinit();
|
||||
self.flex_type_context = saved_flex_type_context;
|
||||
self.poly_context_generation +%= 1;
|
||||
return error.TypeMismatch;
|
||||
}
|
||||
// Decref the original argument value since patternMatchesBind made a copy
|
||||
arg.decref(&self.runtime_layout_store, roc_ops);
|
||||
}
|
||||
|
||||
try work_stack.push(.{ .apply_continuation = .{ .call_cleanup = .{
|
||||
|
|
@ -15037,7 +15078,7 @@ pub const Interpreter = struct {
|
|||
.did_instantiate = did_instantiate,
|
||||
.call_ret_rt_var = null,
|
||||
.saved_rigid_subst = saved_rigid_subst,
|
||||
.saved_flex_type_context = null,
|
||||
.saved_flex_type_context = saved_flex_type_context,
|
||||
.arg_rt_vars_to_free = null,
|
||||
} } });
|
||||
try work_stack.push(.{ .eval_expr = .{
|
||||
|
|
|
|||
16
test/fx/fold_rev_static_dispatch.roc
Normal file
16
test/fx/fold_rev_static_dispatch.roc
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
app [main!] { pf: platform "./platform/main.roc" }
|
||||
|
||||
import pf.Stdout
|
||||
|
||||
# Test that fold_rev works with static dispatch (method syntax)
|
||||
# Previously this panicked while List.fold_rev(...) worked fine
|
||||
main! = || {
|
||||
Stdout.line!("Start reverse")
|
||||
rev =
|
||||
[1, 2, 3].fold_rev([], |elem, acc| {
|
||||
acc.append(elem)
|
||||
})
|
||||
# rev should be [3, 2, 1]
|
||||
Stdout.line!("Reversed: ${rev.len().to_str()} elements")
|
||||
Stdout.line!("Done")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue