Skip to content

Commit 398ddf2

Browse files
committed
Make function (@f(x)) body end an ambiguity error
This case is ambiguous as it might be either one of the following; require the user to explicitly disambiguate between them ``` function (@f(x),) body end function @f(x) body end ``` For the same reasons, `function ($f) body end` is also ambiguous. Also fix parsing of `function (f(x),) end` to correctly emit a tuple.
1 parent 5913117 commit 398ddf2

File tree

2 files changed

+16
-3
lines changed

2 files changed

+16
-3
lines changed

src/parser.jl

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,14 +2110,15 @@ function parse_function_signature(ps::ParseState, is_function::Bool)
21102110
# * The whole function declaration, in parens
21112111
bump(ps, TRIVIA_FLAG)
21122112
is_empty_tuple = peek(ps, skip_newlines=true) == K")"
2113-
opts = parse_brackets(ps, K")") do _, _, _, _
2113+
opts = parse_brackets(ps, K")") do had_commas, had_splat, num_semis, num_subexprs
21142114
_parsed_call = was_eventually_call(ps)
21152115
_needs_parse_call = peek(ps, 2) KSet"( ."
2116-
_is_anon_func = !_needs_parse_call && !_parsed_call
2116+
_is_anon_func = (!_needs_parse_call && !_parsed_call) || had_commas
21172117
return (needs_parameters = _is_anon_func,
21182118
is_anon_func = _is_anon_func,
21192119
parsed_call = _parsed_call,
2120-
needs_parse_call = _needs_parse_call)
2120+
needs_parse_call = _needs_parse_call,
2121+
maybe_grouping_parens = !had_commas && !had_splat && num_semis == 0 && num_subexprs == 1)
21212122
end
21222123
is_anon_func = opts.is_anon_func
21232124
parsed_call = opts.parsed_call
@@ -2128,7 +2129,14 @@ function parse_function_signature(ps::ParseState, is_function::Bool)
21282129
# function (x,y) end ==> (function (tuple-p x y) (block))
21292130
# function (x=1) end ==> (function (tuple-p (= x 1)) (block))
21302131
# function (;x=1) end ==> (function (tuple-p (parameters (= x 1))) (block))
2132+
# function (f(x),) end ==> (function (tuple-p (call f x)) (block))
2133+
ambiguous_parens = opts.maybe_grouping_parens &&
2134+
peek_behind(ps).kind in KSet"macrocall $"
21312135
emit(ps, mark, K"tuple", PARENS_FLAG)
2136+
if ambiguous_parens
2137+
# Got something like `(@f(x))`. Is it anon `(@f(x),)` or named sig `@f(x)` ??
2138+
emit(ps, mark, K"error", error="Ambiguous signature. Add a trailing comma if this is a 1-argument anonymous function; remove parentheses if this is a macro call acting as function signature.")
2139+
end
21322140
elseif is_empty_tuple
21332141
# Weird case which is consistent with parse_paren but will be
21342142
# rejected in lowering

test/parser.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,11 @@ tests = [
563563
"function (x,y) end" => "(function (tuple-p x y) (block))"
564564
"function (x=1) end" => "(function (tuple-p (= x 1)) (block))"
565565
"function (;x=1) end" => "(function (tuple-p (parameters (= x 1))) (block))"
566+
"function (f(x),) end" => "(function (tuple-p (call f x)) (block))"
567+
"function (@f(x);) end" => "(function (tuple-p (macrocall-p @f x) (parameters)) (block))"
568+
"function (@f(x)...) end" => "(function (tuple-p (... (macrocall-p @f x))) (block))"
569+
"function (@f(x)) end" => "(function (error (tuple-p (macrocall-p @f x))) (block))"
570+
"function (\$f) end" => "(function (error (tuple-p (\$ f))) (block))"
566571
"function ()(x) end" => "(function (call (tuple-p) x) (block))"
567572
"function (A).f() end" => "(function (call (. (parens A) f)) (block))"
568573
"function (:)() end" => "(function (call (parens :)) (block))"

0 commit comments

Comments
 (0)