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

Allow macrocall as function sig #55040

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ Language changes
expression within a given `:toplevel` expression to make use of macros
defined earlier in the same `:toplevel` expression. ([#53515])

- Macros in function-signature-position no longer require parentheses. E.g. `function @main(args) ... end` is now permitted,
whereas `function (@main)(args) ... end` was required in prior Julia versions.

Compiler/Runtime improvements
-----------------------------

Expand Down
15 changes: 8 additions & 7 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ The `@main` macro may be used standalone or as part of the function definition,
case, parentheses are required. In particular, the following are equivalent:

```
function (@main)(args)
function @main(args)
println("Hello World")
end
```
Expand All @@ -618,7 +618,7 @@ imported into `Main`, it will be treated as an entrypoint in `Main`:
```
module MyApp
export main
(@main)(args) = println("Hello World")
@main(args) = println("Hello World")
end
using .MyApp
# `julia` Will execute MyApp.main at the conclusion of script execution
Expand All @@ -628,7 +628,7 @@ Note that in particular, the semantics do not attach to the method
or the name:
```
module MyApp
(@main)(args) = println("Hello World")
@main(args) = println("Hello World")
end
const main = MyApp.main
# `julia` Will *NOT* execute MyApp.main unless there is a separate `@main` annotation in `Main`
Expand All @@ -638,9 +638,6 @@ const main = MyApp.main
This macro is new in Julia 1.11. At present, the precise semantics of `@main` are still subject to change.
"""
macro main(args...)
if !isempty(args)
error("`@main` is expected to be used as `(@main)` without macro arguments.")
end
if isdefined(__module__, :main)
if Base.binding_module(__module__, :main) !== __module__
error("Symbol `main` is already a resolved import in module $(__module__). `@main` must be used in the defining module.")
Expand All @@ -651,5 +648,9 @@ macro main(args...)
global main
global var"#__main_is_entrypoint__#"::Bool = true
end)
esc(:main)
if !isempty(args)
Expr(:call, esc(:main), map(esc, args)...)
else
esc(:main)
end
end
6 changes: 3 additions & 3 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1329,13 +1329,13 @@

(define (valid-func-sig? paren sig)
(and (pair? sig)
(or (eq? (car sig) 'call)
(eq? (car sig) 'tuple)
(or (memq (car sig) '(call tuple))
(and (not paren) (eq? (car sig) 'macrocall))
(and paren (eq? (car sig) 'block))
(and paren (eq? (car sig) '...))
(and (eq? (car sig) '|::|)
(pair? (cadr sig))
(eq? (car (cadr sig)) 'call))
(memq (car (cadr sig)) '(call macrocall)))
(and (eq? (car sig) 'where)
(valid-func-sig? paren (cadr sig))))))

Expand Down
31 changes: 31 additions & 0 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3904,3 +3904,34 @@ module ExtendedIsDefined
@test !$(Expr(:isdefined, GlobalRef(@__MODULE__, :x4), false))
end
end

# PR# 55040 - Macrocall as function sig
@test :(function @f()() end) == :(function (@f)() end)

function callme end
macro callmemacro(args...)
Expr(:call, esc(:callme), map(esc, args)...)
end
function @callmemacro(a::Int)
return 1
end
@callmemacro(b::Float64) = 2
function @callmemacro(a::T, b::T) where T <: Int64
return 3
end
function @callmemacro(a::Int, b::Int, c::Int)::Float64
return 4
end
function @callmemacro(d::String)
(a, b, c)
# ^ Should not be accidentally parsed as an argument list
return 4
end

@test callme(1) === 1
@test callme(2.0) === 2
@test callme(3, 3) === 3
@test callme(4, 4, 4) === 4.0

# Ambiguous 1-arg anymous vs macrosig
@test_parseerror "function (@foo(a)) end"
Loading