Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix body locations for def nodes that have default args #10619

Merged
merged 3 commits into from Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions spec/compiler/normalize/def_spec.cr
Expand Up @@ -231,5 +231,25 @@ module Crystal
other_def = a_def.expand_default_arguments(Program.new, 0, ["abstract"])
other_def.to_s.should eq("def foo:abstract(abstract __arg0)\n options = {}\n @abstract = __arg0\nend")
end

describe "gives correct body location with" do
{"default arg" => "def testing(foo = 5)",
"default arg with restriction" => "def testing(foo : Int = 5)",
"splat arg" => "def testing(*foo : Array)",
"block instance var arg" => "def testing(&@foo : ->)",
}.each do |(suffix1, definition)|
{"with body" => "zzz = 7\n",
"without body" => "",
}.each do |(suffix2, body)|
it "#{suffix1}, #{suffix2}" do
a_def = parse("#{definition}\n#{body}end").as(Def)
actual = a_def.expand_default_arguments(Program.new, 1)

actual.location.should eq Location.new("", line_number: 1, column_number: 1)
actual.body.location.should eq Location.new("", line_number: 2, column_number: 1)
end
end
end
end
end
end
4 changes: 2 additions & 2 deletions src/compiler/crystal/semantic/default_arguments.cr
Expand Up @@ -166,7 +166,7 @@ class Crystal::Def
end

new_body.push body
expansion.body = Expressions.new(new_body)
expansion.body = Expressions.new(new_body).at(body)
else
new_args = [] of ASTNode
body = [] of ASTNode
Expand Down Expand Up @@ -203,7 +203,7 @@ class Crystal::Def
call.expansion = true
body << call

expansion.body = Expressions.new(body)
expansion.body = Expressions.new(body).at(self.body)
end

expansion
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/crystal/semantic/new.cr
Expand Up @@ -224,7 +224,7 @@ module Crystal
init.block_arg = Var.new(block_arg.name).at(self)
end

self.body = Expressions.from(exps).at(self)
self.body = Expressions.from(exps).at(self.body)
end

def self.argless_new(instance_type)
Expand Down
7 changes: 4 additions & 3 deletions src/compiler/crystal/syntax/parser.cr
Expand Up @@ -3573,7 +3573,7 @@ module Crystal
end_location = token_end_location

if @token.keyword?(:end)
body = Expressions.from(extra_assigns)
body = Expressions.from(extra_assigns).at(@token.location)
next_token_skip_space
else
body = parse_expressions
Expand All @@ -3585,7 +3585,7 @@ module Crystal
else
exps.push body
end
body = Expressions.from(exps)
body = Expressions.from(exps).at(body)
end
body, end_location = parse_exception_handler body, implicit: true
end
Expand Down Expand Up @@ -3852,6 +3852,7 @@ module Crystal
uses_arg = false
do_next_token = true
when :INSTANCE_VAR
# Transform `def foo(@x); end` to `def foo(x); @x = x; end`
arg_name = @token.value.to_s[1..-1]
if arg_name == external_name
raise "when specified, external name must be different than internal name", @token
Expand Down Expand Up @@ -4367,7 +4368,7 @@ module Crystal
else
exps.push block_body
end
block_body = Expressions.from exps
block_body = Expressions.from(exps).at(block_body)
end

block_body, end_location = yield block_body
Expand Down