From 4a1563e699b3c79017742de655128e87e497a126 Mon Sep 17 00:00:00 2001 From: Lilith Hafner Date: Thu, 14 Sep 2023 20:16:48 -0500 Subject: [PATCH 1/6] add `@public` macro --- Project.toml | 2 +- README.md | 3 +++ src/Compat.jl | 27 ++++++++++++++++++++++++++- test/runtests.jl | 20 +++++++++++++++++++- 4 files changed, 49 insertions(+), 3 deletions(-) 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..ba9dd17d0 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ changes in `julia`. ## Supported features +* `@public` as an alias for the `public` keyword (no-op on 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..ac76dd1fd 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]) @@ -741,6 +741,31 @@ if VERSION < v"1.10.0-DEV.1404" (lt(o, y[1], x[1]) ? (y[1], merge(x, tail(y), o)...) : (x[1], merge(tail(x), y, o)...)) end +# https://github.com/JuliaLang/julia/pull/50105 +export @public +""" + @public foo, bar, baz + +Equivalent to `public foo, bar, baz` on versions of Julia that support the `public` keyword; +a no-op on versions of Julia that do not support the `public` keyword. +""" +macro public(arg) + symbols = _get_symbols(arg) + if VERSION >= v"1.11.0-DEV.469" + esc(Expr(:public, symbols...)) + end +end + +_get_symbols(symbol::Symbol) = (symbol,) +function _get_symbols(symbols) + if Base.isexpr(symbols, :tuple) && all(x -> x isa Symbol, symbols.args) + symbols.args + else + throw(ArgumentError("cannot mark `$symbols` as public. Try `@public foo, bar, baz`.")) + end +end + + include("deprecated.jl") end # module Compat diff --git a/test/runtests.jl b/test/runtests.jl index 7c74c8976..c34735034 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,21 @@ end @test_throws ArgumentError("1 cannot be sorted") sort(1) end end + +module Mod50105 + using Compat + @public foo, bar, baz +end + +# https://github.com/JuliaLang/julia/pull/50105 +@testset "@public" begin + @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) + @test Base.isexported(Mod50105, :bar) === false + VERSION >= v"1.11.0-DEV.469" && @test Base.ispublic(Mod50105, :bar) + + @test_throws LoadError @eval @public 4, bar + @test_throws LoadError @eval @public foo bar +end From 0c90fae7a869a5f526a4cb13620ea077fc30456e Mon Sep 17 00:00:00 2001 From: Lilith Orion Hafner Date: Fri, 15 Sep 2023 08:29:15 -0500 Subject: [PATCH 2/6] compat with 1.5 --- src/Compat.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compat.jl b/src/Compat.jl index ac76dd1fd..ad23f905c 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -758,7 +758,7 @@ end _get_symbols(symbol::Symbol) = (symbol,) function _get_symbols(symbols) - if Base.isexpr(symbols, :tuple) && all(x -> x isa Symbol, symbols.args) + if symbols isa Expr && symbols.head == :tuple && all(x -> x isa Symbol, symbols.args) symbols.args else throw(ArgumentError("cannot mark `$symbols` as public. Try `@public foo, bar, baz`.")) From eaa225980769fa59edf32ed5f4a5518f3d918fe1 Mon Sep 17 00:00:00 2001 From: Lilith Hafner Date: Fri, 15 Sep 2023 10:06:34 -0500 Subject: [PATCH 3/6] switch syntax to `@compat public foo, bar` --- README.md | 2 +- src/Compat.jl | 25 ------------------------- src/compatmacro.jl | 22 ++++++++++++++++++++-- test/runtests.jl | 11 ++++++----- 4 files changed, 27 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index ba9dd17d0..b59db731c 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ changes in `julia`. ## Supported features -* `@public` as an alias for the `public` keyword (no-op on Julia 1.10 and earlier). ([#50105]) (since Compat 4.10.0) +* `@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) diff --git a/src/Compat.jl b/src/Compat.jl index ad23f905c..49356523c 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -741,31 +741,6 @@ if VERSION < v"1.10.0-DEV.1404" (lt(o, y[1], x[1]) ? (y[1], merge(x, tail(y), o)...) : (x[1], merge(tail(x), y, o)...)) end -# https://github.com/JuliaLang/julia/pull/50105 -export @public -""" - @public foo, bar, baz - -Equivalent to `public foo, bar, baz` on versions of Julia that support the `public` keyword; -a no-op on versions of Julia that do not support the `public` keyword. -""" -macro public(arg) - symbols = _get_symbols(arg) - if VERSION >= v"1.11.0-DEV.469" - esc(Expr(:public, symbols...)) - end -end - -_get_symbols(symbol::Symbol) = (symbol,) -function _get_symbols(symbols) - if symbols isa Expr && symbols.head == :tuple && all(x -> x isa Symbol, symbols.args) - symbols.args - else - throw(ArgumentError("cannot mark `$symbols` as public. Try `@public foo, bar, baz`.")) - end -end - - include("deprecated.jl") end # module Compat diff --git a/src/compatmacro.jl b/src/compatmacro.jl index cfb3568ec..f50f1b742 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,21 @@ 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 + +_get_symbols(symbol::Symbol) = (symbol,) +function _get_symbols(symbols::Expr) + if symbols.head == :tuple && all(x -> x isa Symbol, symbols.args) + symbols.args + else + throw(ArgumentError("cannot mark `$symbols` as public. Try `@compat public foo, bar`.")) + end +end diff --git a/test/runtests.jl b/test/runtests.jl index c34735034..668ed21c6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -727,18 +727,19 @@ end module Mod50105 using Compat - @public foo, bar, baz + @compat public foo, bar, baz end # https://github.com/JuliaLang/julia/pull/50105 -@testset "@public" begin - @public foo_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) @test Base.isexported(Mod50105, :bar) === false VERSION >= v"1.11.0-DEV.469" && @test Base.ispublic(Mod50105, :bar) - @test_throws LoadError @eval @public 4, bar - @test_throws LoadError @eval @public 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 end From b88dced6511675020ddd5f1923b81cc3c614e024 Mon Sep 17 00:00:00 2001 From: Lilith Hafner Date: Sat, 16 Sep 2023 12:37:38 -0500 Subject: [PATCH 4/6] improve tests to catch @mcabbott's objection --- test/runtests.jl | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 668ed21c6..523ac2c4d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -728,6 +728,9 @@ end module Mod50105 using Compat @compat public foo, bar, baz + @compat public @mac1 + @compat public f00, @mac2, @mac3 + @compat public @mac4, @mac5 end # https://github.com/JuliaLang/julia/pull/50105 @@ -736,10 +739,18 @@ end # 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) - @test Base.isexported(Mod50105, :bar) === false - VERSION >= v"1.11.0-DEV.469" && @test Base.ispublic(Mod50105, :bar) + for sym in [:foo, :bar, :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 From dbe7da6e8733f3e6ed891ad0b13f39045b8cfbd8 Mon Sep 17 00:00:00 2001 From: Lilith Hafner Date: Sat, 16 Sep 2023 12:56:29 -0500 Subject: [PATCH 5/6] support macros --- src/compatmacro.jl | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/compatmacro.jl b/src/compatmacro.jl index f50f1b742..aa6ee9e79 100644 --- a/src/compatmacro.jl +++ b/src/compatmacro.jl @@ -49,11 +49,28 @@ macro compat(public::Symbol, symbols_expr::Union{Expr, Symbol}) end end -_get_symbols(symbol::Symbol) = (symbol,) -function _get_symbols(symbols::Expr) - if symbols.head == :tuple && all(x -> x isa Symbol, symbols.args) - symbols.args - else - throw(ArgumentError("cannot mark `$symbols` as public. Try `@compat public foo, bar`.")) +""" + _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 From d74c2f379e89653e5557ddc03d9e032b252507ac Mon Sep 17 00:00:00 2001 From: Lilith Hafner Date: Sat, 16 Sep 2023 12:59:41 -0500 Subject: [PATCH 6/6] test var"#" --- test/runtests.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 523ac2c4d..fe39e2cab 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -727,7 +727,7 @@ end module Mod50105 using Compat - @compat public foo, bar, baz + @compat public foo, var"#", baz @compat public @mac1 @compat public f00, @mac2, @mac3 @compat public @mac4, @mac5 @@ -739,7 +739,7 @@ end # 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, :bar, :baz, Symbol("@mac1"), :f00, Symbol("@mac2"), Symbol("@mac3"), Symbol("@mac4"), Symbol("@mac5")] + 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