diff --git a/lib/typeprof/core/ast.rb b/lib/typeprof/core/ast.rb index 2f86013e..e64f11ac 100644 --- a/lib/typeprof/core/ast.rb +++ b/lib/typeprof/core/ast.rb @@ -397,7 +397,7 @@ def self.create_pattern_node(raw_node, lenv) when :array_node then ArrayNode.new(raw_node, lenv) # for %w[foo bar] when :range_node then RangeNode.new(raw_node, lenv) # TODO: support range pattern correctly - when :lambda_node then LambdaNode.new(raw_node, lenv) # TODO: match by `===` instead of ignoring the subject + when :lambda_node then LambdaNode.new(raw_node, lenv) else raise "unknown pattern node type: #{ raw_node.type }" diff --git a/lib/typeprof/core/ast/value.rb b/lib/typeprof/core/ast/value.rb index d5547ee2..2be8d3ce 100644 --- a/lib/typeprof/core/ast/value.rb +++ b/lib/typeprof/core/ast/value.rb @@ -332,6 +332,18 @@ def install0(genv) class LambdaNode < BlockNode def lambda? = true + # A diagnostic on the `===` call below, such as wrong arity, points at the + # whole lambda. + def mid_code_range = nil + + # `in ->(x) { ... }` matches by calling the lambda with the subject. + def install_pattern0(genv, subject) + recv = install0(genv) + a_args = ActualArguments.new([subject], [false], nil, nil) + @changes.add_method_call_box(genv, recv, :===, a_args, false) + recv + end + # A lambda is entered like a method, so every parameter kind binds, not just # the positionals a block is handed. def build_formals(genv, blenv, f_args) diff --git a/scenario/patterns/lambda_pat_subject.rb b/scenario/patterns/lambda_pat_subject.rb new file mode 100644 index 00000000..98d517a1 --- /dev/null +++ b/scenario/patterns/lambda_pat_subject.rb @@ -0,0 +1,32 @@ +## update: test.rb +def pr(x) + x +end + +def check(x) + case x + in ->(i) { pr(i).foo } + :a + end +end + +def check_arity(x) + case x + in ->(i, j) { true } + :a + end +end + +check(0) +check_arity(0) + +## diagnostics +(7,19)-(7,22): undefined method: Integer#foo +(14,5)-(14,22): wrong number of arguments (1 for 2) + +## assert +class Object + def pr: (Integer) -> Integer + def check: (Integer) -> :a + def check_arity: (Integer) -> :a +end