From ac62b6da04c5b4d301ca46955c15c25efca81620 Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Mon, 28 Sep 2026 19:50:01 +0900 Subject: [PATCH] Analyze a pattern guard after the pattern binds its variables IfPatternNode installed the guard before the guarded pattern, so a variable bound by the pattern was still nil in the guard, and a common guard like `in [x] if x.even?` reported "undefined method: nil#even?". Ruby evaluates the guard after the pattern matches, so install the pattern first. Co-Authored-By: Claude Opus 5.5 --- lib/typeprof/core/ast/pattern.rb | 3 ++- scenario/patterns/guard_binding.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 scenario/patterns/guard_binding.rb diff --git a/lib/typeprof/core/ast/pattern.rb b/lib/typeprof/core/ast/pattern.rb index eed2da94..3ecccb48 100644 --- a/lib/typeprof/core/ast/pattern.rb +++ b/lib/typeprof/core/ast/pattern.rb @@ -153,8 +153,9 @@ def initialize(raw_node, lenv) def subnodes = { cond:, body: } def install_pattern0(genv, subject) - @cond.install(genv) + # The guard is evaluated after the pattern binds its variables @body.install_pattern(genv, subject) + @cond.install(genv) subject end end diff --git a/scenario/patterns/guard_binding.rb b/scenario/patterns/guard_binding.rb new file mode 100644 index 00000000..70c1fc89 --- /dev/null +++ b/scenario/patterns/guard_binding.rb @@ -0,0 +1,30 @@ +## update: test.rb +def cond?(x) + x +end + +def check_if(v) + case v + in [x] if cond?(x).even? + x + end +end + +def check_unless(v) + case v + in [_, y] unless cond?(y).even? + y + end +end + +check_if([1]) +check_unless([:a, 1]) + +## diagnostics + +## assert +class Object + def cond?: (Integer) -> Integer + def check_if: ([Integer]) -> Integer + def check_unless: ([:a, Integer]) -> Integer +end