Skip to content

Commit

Permalink
Showing 4 changed files with 46 additions and 6 deletions.
16 changes: 16 additions & 0 deletions spec/compiler/normalize/case_spec.cr
Original file line number Diff line number Diff line change
@@ -33,6 +33,22 @@ describe "Normalize: case" do
assert_expand "case x; when .foo(1); 2; end", "__temp_1 = x\nif __temp_1.foo(1)\n 2\nend"
end

it "normalizes case with implicit responds_to? (#3040)" do
assert_expand "case x; when .responds_to?(:foo); 2; end", "__temp_1 = x\nif __temp_1.responds_to?(:foo)\n 2\nend"
end

it "normalizes case with implicit is_a? (#3040)" do
assert_expand "case x; when .is_a?(T); 2; end", "__temp_1 = x\nif __temp_1.is_a?(T)\n 2\nend"
end

it "normalizes case with implicit as (#3040)" do
assert_expand "case x; when .as(T); 2; end", "__temp_1 = x\nif __temp_1.as(T)\n 2\nend"
end

it "normalizes case with implicit as? (#3040)" do
assert_expand "case x; when .as?(T); 2; end", "__temp_1 = x\nif __temp_1.as?(T)\n 2\nend"
end

it "normalizes case with assignment" do
assert_expand "case x = 1; when 2; 3; end", "x = 1\nif 2 === x\n 3\nend"
end
4 changes: 4 additions & 0 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
@@ -888,6 +888,10 @@ describe "Parser" do
it_parses "case\n1\nwhen 1\n2\nend\nif a\nend", [Case.new(1.int32, [When.new([1.int32] of ASTNode, 2.int32)]), If.new("a".call)]

it_parses "case 1\nwhen .foo\n2\nend", Case.new(1.int32, [When.new([Call.new(ImplicitObj.new, "foo")] of ASTNode, 2.int32)])
it_parses "case 1\nwhen .responds_to?(:foo)\n2\nend", Case.new(1.int32, [When.new([RespondsTo.new(ImplicitObj.new, "foo")] of ASTNode, 2.int32)])
it_parses "case 1\nwhen .is_a?(T)\n2\nend", Case.new(1.int32, [When.new([IsA.new(ImplicitObj.new, "T".path)] of ASTNode, 2.int32)])
it_parses "case 1\nwhen .as(T)\n2\nend", Case.new(1.int32, [When.new([Cast.new(ImplicitObj.new, "T".path)] of ASTNode, 2.int32)])
it_parses "case 1\nwhen .as?(T)\n2\nend", Case.new(1.int32, [When.new([NilableCast.new(ImplicitObj.new, "T".path)] of ASTNode, 2.int32)])
it_parses "case when 1\n2\nend", Case.new(nil, [When.new([1.int32] of ASTNode, 2.int32)])
it_parses "case \nwhen 1\n2\nend", Case.new(nil, [When.new([1.int32] of ASTNode, 2.int32)])
it_parses "case {1, 2}\nwhen {3, 4}\n5\nend", Case.new(TupleLiteral.new([1.int32, 2.int32] of ASTNode), [When.new([TupleLiteral.new([3.int32, 4.int32] of ASTNode)] of ASTNode, 5.int32)])
20 changes: 16 additions & 4 deletions src/compiler/crystal/semantic/literal_expander.cr
Original file line number Diff line number Diff line change
@@ -552,6 +552,12 @@ module Crystal

right_side = temp_var.clone

check_implicit_obj Call
check_implicit_obj RespondsTo
check_implicit_obj IsA
check_implicit_obj Cast
check_implicit_obj NilableCast

case cond
when NilLiteral
return IsA.new(right_side, Path.global("Nil"))
@@ -560,10 +566,6 @@ module Crystal
when Call
obj = cond.obj
case obj
when ImplicitObj
implicit_call = cond.clone.as(Call)
implicit_call.obj = temp_var.clone
return implicit_call
when Path
if cond.name == "class"
return IsA.new(right_side, Metaclass.new(obj.clone).at(obj))
@@ -578,6 +580,16 @@ module Crystal
Call.new(cond, "===", right_side)
end

macro check_implicit_obj(type)
if cond.is_a?({{type}})
if (obj = cond.obj).is_a?(ImplicitObj)
implicit_call = cond.clone.as({{type}})
implicit_call.obj = temp_var.clone
return implicit_call
end
end
end

private def regex_new_call(node, value)
Call.new(Path.global("Regex").at(node), "new", value, regex_options(node)).at(node)
end
12 changes: 10 additions & 2 deletions src/compiler/crystal/syntax/parser.cr
Original file line number Diff line number Diff line change
@@ -2479,8 +2479,16 @@ module Crystal
def parse_when_expression(cond)
if cond && @token.type == :"."
next_token
call = parse_var_or_call(force_call: true).as(Call)
call.obj = ImplicitObj.new
call = parse_var_or_call(force_call: true)
case call
when Call then call.obj = ImplicitObj.new
when RespondsTo then call.obj = ImplicitObj.new
when IsA then call.obj = ImplicitObj.new
when Cast then call.obj = ImplicitObj.new
when NilableCast then call.obj = ImplicitObj.new
else
raise "Bug: expected Call, RespondsTo, IsA, Cast or NilableCast"
end
call
else
parse_op_assign_no_control

0 comments on commit 299bbdd

Please sign in to comment.