Skip to content

Commit b6e65f2

Browse files
authored
Support import renaming through at-compat macro. (#725)
1 parent 786d0d8 commit b6e65f2

File tree

4 files changed

+82
-2
lines changed

4 files changed

+82
-2
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "Compat"
22
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
3-
version = "3.20.0"
3+
version = "3.21.0"
44

55
[deps]
66
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ changes in `julia`.
5555

5656
## Supported features
5757

58+
* Import renaming is available through the `@compat` macro, e.g. `@compat import LinearAlgebra as LA` and
59+
`@compat import LinearAlgebra: cholesky as c, lu as l`. *Note:* Import renaming of macros is not
60+
supported due to differences in parsing behavior ([#37396]). (since Compat 3.21).
61+
5862
* `Compat.parseatom(text::AbstractString, pos::Integer; filename="none")` parses a single
5963
atom from `text` starting at index `pos`. Returns a `Tuple` consisting of the
6064
parsed expression and the index to resume parsing from. ([#35243]) (since Compat 3.20)
@@ -219,3 +223,4 @@ Note that you should specify the correct minimum version for `Compat` in the
219223
[#37559]: https://github.com/JuliaLang/julia/pull/37559
220224
[#29634]: https://github.com/JuliaLang/julia/pull/29634
221225
[#35243]: https://github.com/JuliaLang/julia/pull/35243
226+
[#37396]: https://github.com/JuliaLang/julia/pull/37396

src/compatmacro.jl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,53 @@ _compat(ex) = ex
1616
macro compat(ex)
1717
esc(_compat(ex))
1818
end
19+
20+
# Only the import-renaming usage results in multiple arguments.
21+
# On versions where renaming is supported natively it parses as a
22+
# single expression and thus takes the single-argument @compat
23+
# code-path above
24+
macro compat(ex, exprs...)
25+
@assert VERSION < v"1.6.0-DEV.1157"
26+
if length(exprs) == 2 && Meta.isexpr(ex, :import, 1) && Meta.isexpr(ex.args[1], :.) &&
27+
exprs[1] === :as && exprs[2] isa Symbol
28+
# Matches "import Module(.Submodule) as a"
29+
lhs = Symbol[ex.args[1].args...]
30+
alias = exprs[2]
31+
return _create_import_expression([lhs => alias])
32+
elseif Meta.isexpr(ex, [:import, :using], 1) &&
33+
Meta.isexpr(ex.args[1], :(:)) && length(exprs) % 2 == 0 &&
34+
all(x -> x === :as, exprs[1:2:end-1]) &&
35+
all(x -> Meta.isexpr(x, :tuple, 2), exprs[2:2:end-2]) &&
36+
exprs[end] isa Symbol
37+
# Matches "(import|using) Module(.Submodule): a as b(, c as d)
38+
syms = Symbol[ ex.args[1].args[2].args[1] ]
39+
foreach(x -> x isa Symbol ? push!(syms, x) : append!(syms, x.args), exprs[2:2:end])
40+
41+
path_aliases = Pair{Vector{Symbol},Symbol}[]
42+
init = ex.args[1].args[1].args
43+
for i in 1:2:length(syms)
44+
push!(path_aliases, Symbol[init; syms[i]] => syms[i+1])
45+
end
46+
return _create_import_expression(path_aliases)
47+
else
48+
throw(ArgumentError("invalid use of @compat"))
49+
end
50+
end
51+
52+
function _create_import_expression(path_aliases::Vector{Pair{Vector{Symbol}, Symbol}})
53+
# Create an gensymd baremodule to hide names in
54+
s = gensym()
55+
# Create all import/const exprs
56+
import_exprs = Expr[]
57+
const_exprs = Expr[]
58+
for (path, alias) in path_aliases
59+
import_expr = Expr(:import, Expr(:., path...))
60+
push!(import_exprs, import_expr)
61+
rhs_expr = Expr(:escape, Expr(:., s, QuoteNode(last(path))))
62+
const_expr = Expr(:const, Expr(:global, Expr(:(=), alias, rhs_expr)))
63+
push!(const_exprs, const_expr)
64+
end
65+
module_expr = Expr(:module, false, Expr(:escape, s), Expr(:block, import_exprs...))
66+
return_expr = Expr(:toplevel, module_expr, const_exprs..., nothing)
67+
return return_expr
68+
end

test/runtests.jl

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,4 +753,29 @@ end
753753

754754
include("iterators.jl")
755755

756-
nothing
756+
# Import renaming, https://github.com/JuliaLang/julia/pull/37396,
757+
# and https://github.com/JuliaLang/julia/pull/37965
758+
module ImportRename
759+
using Compat
760+
@compat import LinearAlgebra as LA
761+
@compat import LinearAlgebra.BLAS as BL
762+
@compat import LinearAlgebra.BLAS: dotc as dc
763+
@compat import LinearAlgebra: cholesky as chol, lu as lufact
764+
@compat using LinearAlgebra.BLAS: hemm as hm
765+
end
766+
767+
import .ImportRename
768+
import LinearAlgebra
769+
770+
@testset "import renaming" begin
771+
@test ImportRename.LA === LinearAlgebra
772+
@test !isdefined(ImportRename, :LinearAlgebra)
773+
@test ImportRename.BL === LinearAlgebra.BLAS
774+
@test !isdefined(ImportRename, :BLAS)
775+
@test ImportRename.dc === LinearAlgebra.BLAS.dotc
776+
@test !isdefined(ImportRename, :dotc)
777+
@test ImportRename.chol === LinearAlgebra.cholesky
778+
@test ImportRename.lufact === LinearAlgebra.lu
779+
@test ImportRename.hm === LinearAlgebra.BLAS.hemm
780+
@test !isdefined(ImportRename, :hemm)
781+
end

0 commit comments

Comments
 (0)