Skip to content

Commit

Permalink
it
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed May 3, 2020
1 parent c829076 commit ba0b041
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
28 changes: 28 additions & 0 deletions spec/compiler/semantic/implicit_block_argument_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,32 @@ describe "Semantic: implicit block argument" do
foo &{&1, &2, &3}
)) { tuple_of [int32, char, bool] }
end

it "errors if 'it' variable outside of block (assign)" do
assert_error %(
it = 1
),
"implcit block argument 'it' can only be used inside a block"
end

it "errors if 'it' argless call outside of block (assign)" do
assert_error %(
it
),
"implcit block argument 'it' can only be used inside a block"
end

it "uses implicit block argument 'it' with call" do
assert_type(%(
def foo
yield 1
end
def bar(x)
x
end
foo &bar(it)
)) { int32 }
end
end
30 changes: 28 additions & 2 deletions src/compiler/crystal/semantic/implicit_block_argument.cr
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ module Crystal
end
end

def visit(node : Call)
if node.args.empty? && !node.named_args && node.name == "it"
@has_implicit_block_arguments = true
false
else
true
end
end

def visit(node : ASTNode)
!@has_implicit_block_arguments
end
Expand All @@ -42,7 +51,22 @@ module Crystal
@block = Block.new
end

def transform(node : ExpandableNode | Call)
def transform(node : Call)
if node.is_a?(Call) && node.args.empty? && !node.named_args && node.name == "it"
return replace(node, 1)
end

expanded = node.expanded
if expanded
node.expanded = expanded.transform(self)
node
else
# TODO: don't go inside Call block_arg
super
end
end

def transform(node : ExpandableNode)
expanded = node.expanded
if expanded
node.expanded = expanded.transform(self)
Expand All @@ -59,8 +83,10 @@ module Crystal
end

def transform(node : ImplicitBlockArgument)
number = node.number
replace(node, node.number)
end

def replace(node, number)
args = @block.args ||= [] of Var

(number - args.size).times do |i|
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/crystal/semantic/main_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,10 @@ module Crystal
end

def type_assign(target : Var, value, node, restriction = nil)
if target.name == "it"
node.raise "implcit block argument 'it' can only be used inside a block"
end

value.accept self

var_name = target.name
Expand Down Expand Up @@ -1291,6 +1295,10 @@ module Crystal
end

def visit(node : Call)
if node.args.empty? && !node.named_args && node.name == "it"
node.raise "implcit block argument 'it' can only be used inside a block"
end

prepare_call(node)

if expand_macro(node)
Expand Down

0 comments on commit ba0b041

Please sign in to comment.