diff --git a/Project.toml b/Project.toml index 845596f96..8af5b2682 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "Compat" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.9.0" +version = "4.10.0" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/README.md b/README.md index 8ffb9d174..b59db731c 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ changes in `julia`. ## Supported features +* `@compat public foo, bar` marks `foo` and `bar` as public in Julia 1.11+ and is a no-op in Julia 1.10 and earlier. ([#50105]) (since Compat 4.10.0) + * `sort` for `NTuple` and other iterables. ([#46104]) (since Compat 4.9.0) * `redirect_stdio`, for simple stream redirection. ([#37978]) (since Compat 4.8.0) @@ -172,3 +174,4 @@ Note that you should specify the correct minimum version for `Compat` in the [#43852]: https://github.com/JuliaLang/julia/issues/43852 [#46104]: https://github.com/JuliaLang/julia/issues/46104 [#48038]: https://github.com/JuliaLang/julia/issues/48038 +[#50105]: https://github.com/JuliaLang/julia/issues/50105 diff --git a/src/Compat.jl b/src/Compat.jl index 8bc244917..49356523c 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -389,7 +389,7 @@ end if VERSION < v"1.9.0-DEV.1163" import Base: IteratorSize, HasLength, HasShape, OneTo export stack - + """ stack(iter; [dims]) diff --git a/src/compatmacro.jl b/src/compatmacro.jl index cfb3568ec..aa6ee9e79 100644 --- a/src/compatmacro.jl +++ b/src/compatmacro.jl @@ -13,11 +13,11 @@ function _compat(ex::Expr) @static if VERSION < v"1.7.0-DEV.364" if Meta.isexpr(ex, :(=)) && Meta.isexpr(ex.args[1], :tuple) && Meta.isexpr(ex.args[1].args[1], :parameters) - + ex = _destructure_named_tuple(ex) end end - + return Expr(ex.head, map(_compat, ex.args)...) end @@ -39,3 +39,38 @@ function _destructure_named_tuple(ex::Expr) push!(ex.args, values) return ex end + +# https://github.com/JuliaLang/julia/pull/50105 +macro compat(public::Symbol, symbols_expr::Union{Expr, Symbol}) + public == :public || throw(ArgumentError("Invalid Syntax: `@compat $public $symbols_expr`")) + symbols = _get_symbols(symbols_expr) + if VERSION >= v"1.11.0-DEV.469" + esc(Expr(:public, symbols...)) + end +end + +""" + _valid_macro(expr) + +Check if `expr` is a valid macro call with no arguments. +""" +_valid_macro(expr) = Meta.isexpr(expr, :macrocall) && length(expr.args) == 2 && + expr.args[1] isa Symbol && string(expr.args[1])[1] == '@' && + expr.args[2] isa LineNumberNode + +_get_symbols(symbol::Symbol) = [symbol] +function _get_symbols(expr::Expr) + _valid_macro(expr) && return [expr.args[1]] + expr.head == :tuple || throw(ArgumentError("cannot mark `$expr` as public. Try `@compat public foo, bar`.")) + symbols = Vector{Symbol}(undef, length(expr.args)) + for (i, arg) in enumerate(expr.args) + if arg isa Symbol + symbols[i] = arg + elseif _valid_macro(arg) + symbols[i] = arg.args[1] + else + throw(ArgumentError("cannot mark `$arg` as public. Try `@compat public foo, bar`.")) + end + end + symbols +end diff --git a/test/runtests.jl b/test/runtests.jl index 7c74c8976..fe39e2cab 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -238,7 +238,7 @@ end # https://github.com/JuliaLang/julia/pull/43852 @testset "@assume_effects" begin - # ensure proper macro hygiene across versions + # ensure proper macro hygiene across versions Compat.@assume_effects :total foo() = true Compat.@assume_effects bar() = true @test foo() @@ -724,3 +724,33 @@ end @test_throws ArgumentError("1 cannot be sorted") sort(1) end end + +module Mod50105 + using Compat + @compat public foo, var"#", baz + @compat public @mac1 + @compat public f00, @mac2, @mac3 + @compat public @mac4, @mac5 +end + +# https://github.com/JuliaLang/julia/pull/50105 +@testset "@compat public" begin + @compat public foo_50105 + # foo_50105 = 4 # Uncommenting this line would cause errors due to https://github.com/JuliaLang/julia/issues/51325 + @test Base.isexported(@__MODULE__, :foo_50105) === false + VERSION >= v"1.11.0-DEV.469" && @test Base.ispublic(@__MODULE__, :foo_50105) + for sym in [:foo, Symbol("#"), :baz, Symbol("@mac1"), :f00, Symbol("@mac2"), Symbol("@mac3"), Symbol("@mac4"), Symbol("@mac5")] + @test Base.isexported(Mod50105, sym) === false + VERSION >= v"1.11.0-DEV.469" && @test Base.ispublic(Mod50105, sym) + end + + @test_throws LoadError @eval @compat public 4, bar + @test_throws LoadError @eval @compat public foo bar + @test_throws LoadError @eval @compat publac foo, bar + @test_throws LoadError @eval @compat public 4, @bar + @test_throws LoadError @eval @compat public foo @bar + @test_throws LoadError @eval @compat publac foo, @bar + @test_throws LoadError @eval @compat public @bar, 4 + @test_throws LoadError @eval @compat public @bar foo + @test_throws LoadError @eval @compat publac @bar, foo +end