roc icon indicating copy to clipboard operation
roc copied to clipboard

Fix lookup crash for tags with arguments

Open mpizenberg opened this issue 3 weeks ago • 3 comments

Here is the report I got with Claude for this error, corresponding to issue #8637

Roc programs using tag patterns with arguments in lambda parameters would crash with:

e_lookup_local: definition not found in current scope

Failing Example

Iter(s) := [It(s)].{
    identity = |It(val)| It(val)  # Crashes - 'val' not found
}

Working Example

Iter(s) := [It(s)].{
    identity = |x| x  # Works - simple pattern
}

Root Cause

The interpreter was directly appending parameter patterns to bindings instead of using patternMatchesBind. This meant:

  1. For simple patterns like |x|, a binding was created for x
  2. For tag patterns like |It(val)|, only the outer It pattern was bound, not the inner val variable ✗
  3. When the lambda body tried to access val, it couldn't find it in the bindings

Solution

Replace direct bindings.append() calls with patternMatchesBind() calls. This properly handles complex patterns by recursively creating bindings for all sub-patterns.

Code Change (src/eval/interpreter.zig:15031-15045)

Before:

try self.active_closures.append(method_func);
try self.bindings.append(.{
    .pattern_idx = params[0],
    .value = receiver_value,
    .expr_idx = null,
    .source_env = self.env,
});

After:

try self.active_closures.append(method_func);

// Bind receiver using patternMatchesBind to properly handle tag patterns
const receiver_param_rt_var = try self.translateTypeVar(self.env, can.ModuleEnv.varFrom(params[0]));
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();
    receiver_value.decref(&self.runtime_layout_store, roc_ops);
    method_func.decref(&self.runtime_layout_store, roc_ops);
    return error.TypeMismatch;
}
receiver_value.decref(&self.runtime_layout_store, roc_ops);

Additional Locations

The same bug exists in 6 other locations where parameters are bound without using patternMatchesBind:

  • Line 2165: to_inspect method call
  • Line 6987: inspect method binding
  • Line 14257: unary operator method
  • Line 969-980: comparison function parameters (2 locations)
  • Lines 15965-15975 and 16047-16057: sort comparison function

These should be fixed similarly to prevent the same issue in those contexts.

mpizenberg avatar Dec 13 '25 12:12 mpizenberg

I haven’t had the time to investigate the other places where Claude claims there is the same problem. Don’t know if you want to do it in this PR too or in follow up PRs

mpizenberg avatar Dec 13 '25 12:12 mpizenberg

I might have a follow up issue related to this change. So let’s not merge it as-is for now.

mpizenberg avatar Dec 13 '25 16:12 mpizenberg

@mpizenberg I'd say land the fix for one problem and then we can do follow-ups separately!

rtfeldman avatar Dec 14 '25 04:12 rtfeldman