Fix nominal pattern bound variable collection (issue #8689)

collectBoundVarsToScratch was not recursing into the backing pattern
for nominal and nominal_external patterns. This caused variables
bound in nominal patterns (e.g., Wrapper.Simple(s)) to not be tracked
as bound variables, leading to them incorrectly being included in the
free variables of match expression bodies.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Richard Feldman 2025-12-16 07:53:38 -05:00
parent bb52264221
commit 9f143f79ec
No known key found for this signature in database
3 changed files with 32 additions and 2 deletions

View file

@ -2534,6 +2534,14 @@ fn collectBoundVarsToScratch(self: *Self, pattern_idx: Pattern.Idx) !void {
}
}
},
.nominal => |n| {
// Recurse into the backing pattern to collect bound variables
try self.collectBoundVarsToScratch(n.backing_pattern);
},
.nominal_external => |n| {
// Recurse into the backing pattern to collect bound variables
try self.collectBoundVarsToScratch(n.backing_pattern);
},
.num_literal,
.small_dec_literal,
.dec_literal,
@ -2541,8 +2549,6 @@ fn collectBoundVarsToScratch(self: *Self, pattern_idx: Pattern.Idx) !void {
.frac_f64_literal,
.str_literal,
.underscore,
.nominal,
.nominal_external,
.runtime_error,
=> {},
}

View file

@ -243,6 +243,11 @@ pub const io_spec_tests = [_]TestSpec{
.io_spec = "1>is ok",
.description = "Regression test: List.get with method syntax (issue #8662)",
},
.{
.roc_file = "test/fx/issue8689.roc",
.io_spec = "1>hello",
.description = "Regression test: Field access on record payload in tag union wrapped by opaque type (issue #8689)",
},
};
/// Get the total number of IO spec tests

19
test/fx/issue8689.roc Normal file
View file

@ -0,0 +1,19 @@
app [main!] { pf: platform "./platform/main.roc" }
import pf.Stdout
Wrapper := [
WithRecord({ name : Str, value : U64 }),
Simple(Str),
]
getName : Wrapper -> Str
getName = |w| match w {
Wrapper.Simple(s) => s
Wrapper.WithRecord(payload) => payload.name
}
main! = || {
wrapper = Wrapper.WithRecord({ name: "hello", value: 42 })
Stdout.line!(getName(wrapper))
}