Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2114dc02196a
Choose a base ref
...
head repository: crystal-lang/crystal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 46fd4aca14d4
Choose a head ref
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Feb 16, 2017

  1. Fixed #3969: Compiler crash when capturing block in dispatch with non…

    …-capturing method
    Ary Borenszweig committed Feb 16, 2017
    Copy the full SHA
    15929e4 View commit details
  2. Copy the full SHA
    46fd4ac View commit details
Showing with 28 additions and 2 deletions.
  1. +16 −0 spec/compiler/codegen/block_spec.cr
  2. +1 −0 spec/compiler/parser/parser_spec.cr
  3. +2 −1 src/compiler/crystal/codegen/call.cr
  4. +9 −1 src/compiler/crystal/syntax/parser.cr
16 changes: 16 additions & 0 deletions spec/compiler/codegen/block_spec.cr
Original file line number Diff line number Diff line change
@@ -1493,4 +1493,20 @@ describe "Code gen: block" do
end
)).to_i.should eq(123)
end

it "dispatches with captured and non-captured block (#3969)" do
run(%(
def fn(x : Int32, &block)
x
end
def fn(x : Char, &block : -> Int32)
block.call
end
a = fn(1 || 'a') { 2 }
b = fn('a' || 1) { 2 }
a + b
)).to_i.should eq(3)
end
end
1 change: 1 addition & 0 deletions spec/compiler/parser/parser_spec.cr
Original file line number Diff line number Diff line change
@@ -498,6 +498,7 @@ describe "Parser" do
it_parses "foo { |a| 1 }", Call.new(nil, "foo", block: Block.new(["a".var], 1.int32))
it_parses "foo { |a, b| 1 }", Call.new(nil, "foo", block: Block.new(["a".var, "b".var], 1.int32))
it_parses "1.foo do; 1; end", Call.new(1.int32, "foo", block: Block.new(body: 1.int32))
it_parses "a b() {}", Call.new(nil, "a", Call.new(nil, "b", block: Block.new))

it_parses "foo { |a, (b, c), (d, e)| a; b; c; d; e }", Call.new(nil, "foo",
block: Block.new(["a".var, "__arg0".var, "__arg1".var],
3 changes: 2 additions & 1 deletion src/compiler/crystal/codegen/call.cr
Original file line number Diff line number Diff line change
@@ -25,7 +25,8 @@ class Crystal::CodeGenVisitor
return false if @builder.end

if block = node.block
if fun_literal = block.fun_literal
# A block might turn into a proc literal but not be used if it particpates in a dispatch
if (fun_literal = block.fun_literal) && node.target_def.uses_block_arg?
codegen_call_with_block_as_fun_literal(node, fun_literal, owner, call_args)
else
codegen_call_with_block(node, block, owner, call_args)
10 changes: 9 additions & 1 deletion src/compiler/crystal/syntax/parser.cr
Original file line number Diff line number Diff line change
@@ -3636,6 +3636,7 @@ module Crystal
# doesn't have parentheses, we don't parse "x do end" as an invocation
# to a method x with a block. Instead, we just stop on x and we don't
# consume the block, leaving the block for 'foo' to consume.
block = parse_curly_block(block)
elsif @stop_on_do && call_args && call_args.has_parentheses
# This is the case when we have:
#
@@ -3644,6 +3645,7 @@ module Crystal
# end
#
# We don't want to attach the block to `x`, but to `foo`.
block = parse_curly_block(block)
else
block = parse_block(block)
end
@@ -3699,7 +3701,13 @@ module Crystal

raise "block already specified with &" if block
parse_block2 { check_ident :end }
elsif @token.type == :"{"
else
parse_curly_block(block)
end
end

def parse_curly_block(block)
if @token.type == :"{"
raise "block already specified with &" if block
parse_block2 { check :"}" }
else