Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Language changes
* It is now an error to mark a binding as both `public` and `export`ed ([#53664]).
* Errors during `getfield` now raise a new `FieldError` exception type instead of the generic
`ErrorException` ([#54504]).
* 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 @@ -605,7 +605,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 @@ -624,7 +624,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 @@ -634,7 +634,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 @@ -644,9 +644,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 @@ -657,5 +654,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 @@ -4050,3 +4050,34 @@ end
import ..Base
using .Base: zero, zero
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 <: Int
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"