Skip to content

Commit

Permalink
Showing 5 changed files with 43 additions and 23 deletions.
14 changes: 14 additions & 0 deletions spec/compiler/codegen/block_spec.cr
Original file line number Diff line number Diff line change
@@ -1342,4 +1342,18 @@ describe "Code gen: block" do
end
)).to_string.should eq("foo")
end

it "yields inside yield (#682)" do
run(%(
def foo
yield(1, (yield 3))
end
a = 0
foo do |x|
a += x
end
a
)).to_i.should eq(4)
end
end
18 changes: 0 additions & 18 deletions spec/compiler/type_inference/macro_spec.cr
Original file line number Diff line number Diff line change
@@ -357,24 +357,6 @@ describe "Type inference: macro" do
"can't define def inside def"
end

it "uses typeof(self.method) in macro def" do
assert_type(%(
class Foo
macro def foo : typeof(self.bar)
bar
end
end
class Bar < Foo
def bar
1.5
end
end
Bar.new.foo
)) { float64 }
end

it "gives precise location info when doing yield inside macro" do
assert_error %(
macro foo
13 changes: 13 additions & 0 deletions spec/compiler/type_inference/return_spec.cr
Original file line number Diff line number Diff line change
@@ -168,4 +168,17 @@ describe "Type inference: return" do
test
)) { types["Bar"] }
end

it "can use free var in return type (#2492)" do
assert_type(%(
def self.demo(a : A, &block : A -> B) : B
block.call(a)
end
z = demo(1) do |x|
x.to_f
end
z
)) { float64 }
end
end
16 changes: 13 additions & 3 deletions src/compiler/crystal/codegen/codegen.cr
Original file line number Diff line number Diff line change
@@ -1236,13 +1236,23 @@ module Crystal
end

# First accept all yield expressions and assign them to block vars
request_value do
unless node.exps.empty?
exp_values = Array(LLVM::Value).new(node.exps.size)

# We first accept the expressions and store the values, without
# assigning them to the block vars yet because we might have
# a nested yield that would override a block argument's value
node.exps.each_with_index do |exp, i|
accept exp
request_value do
accept exp
end
exp_values << @last
end

node.exps.each_with_index do |exp, i|
if arg = block.args[i]?
block_var = block_context.vars[arg.name]
assign block_var.pointer, block_var.type, exp.type, @last
assign block_var.pointer, block_var.type, exp.type, exp_values[i]
end
end
end
5 changes: 3 additions & 2 deletions src/compiler/crystal/semantic/call.cr
Original file line number Diff line number Diff line change
@@ -435,7 +435,8 @@ class Crystal::Call
self_type = match_owner.instance_type
root_type = self_type.ancestors.find(&.instance_of?(match.def.owner.instance_type)) || self_type
end
return_type = TypeLookup.lookup(root_type, typed_def_return_type, match_owner.instance_type).virtual_type
type_lookup = MatchTypeLookup.new(self, match.context)
return_type = type_lookup.lookup_node_type(typed_def_return_type)
typed_def.freeze_type = return_type
typed_def.type = return_type if return_type.no_return?
end
@@ -922,7 +923,7 @@ class Crystal::Call
end

def visit(node : Self)
@type = @context.owner
@type = @context.owner.instance_type
false
end

0 comments on commit 072f36a

Please sign in to comment.