Skip to content

Commit

Permalink
virtualprocess: handle import Package as Alias syntax (#553)
Browse files Browse the repository at this point in the history
fix #521
  • Loading branch information
aviatesk authored Jul 15, 2023
1 parent 15d42eb commit efea99b
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 53 deletions.
110 changes: 62 additions & 48 deletions src/toplevel/virtualprocess.jl
Original file line number Diff line number Diff line change
Expand Up @@ -651,23 +651,8 @@ function _virtual_process!(res::VirtualProcessResult,
# TODO recursive analysis on dependencies?
pkgid = config.pkgid
if pkgid !== nothing && !isexpr(ex, :export)
modpath = name = alias = nothing
if @capture(ex, import modpath__)
head = :import
elseif @capture(ex, using modpath__)
head = :using
elseif @capture(ex, import modpath__: name_)
head = :import
elseif @capture(ex, using modpath__: name_)
head = :using
elseif @capture(ex, import modpath__: name_ as alias_)
head = :import
elseif @capture(ex, using modpath__: name_ as alias_)
head = :using
else
error(lazy"unexpected module usage found: $ex")
end
modpath = modpath::Vector{Any}
module_usage = pattern_match_module_usage(ex)
(; modpath) = module_usage
dep = first(modpath)::Symbol
if !(dep === :. || # relative module doesn't need to be fixed
dep === :Base || dep === :Core) # modules available by default
Expand Down Expand Up @@ -697,13 +682,8 @@ function _virtual_process!(res::VirtualProcessResult,
end
pushfirst!(modpath, :.)
end
if isa(alias, Symbol) && isa(name, Symbol)
ex = form_module_usage_alias(head, modpath, name, alias)
elseif isa(name, Symbol)
ex = form_module_usage_specific(head, modpath, name)
else
ex = form_module_usage(head, modpath)
end
fixed_module_usage = ModuleUsage(module_usage; modpath)
ex = form_module_usage(fixed_module_usage)
end
end
# `scrub_offset = 3` corresponds to `with_err_handling` -> `f` -> `Core.eval`
Expand Down Expand Up @@ -871,6 +851,57 @@ function split_module_path!(m::Module, ret)
push!(ret, nameof(m))
end

struct ModuleUsage
head::Symbol
modpath::Vector{Any}
name::Union{Symbol,Nothing}
alias::Union{Symbol,Nothing}
end
function ModuleUsage(m::ModuleUsage;
head::Symbol = m.head,
modpath::Vector{Any} = m.modpath,
name::Union{Symbol,Nothing} = m.name,
alias::Union{Symbol,Nothing} = m.alias)
return ModuleUsage(head, modpath, name, alias)
end

function pattern_match_module_usage(usage::Expr)
modpath = name = alias = nothing
if @capture(usage, import modpath__)
head = :import
elseif @capture(usage, using modpath__)
head = :using
elseif @capture(usage, import modpath__: name_)
head = :import
elseif @capture(usage, using modpath__: name_)
head = :using
elseif @capture(usage, import modpath__ as alias_)
head = :import
elseif @capture(usage, import modpath__: name_ as alias_)
head = :import
elseif @capture(usage, using modpath__: name_ as alias_)
head = :using
else
error(lazy"unexpected module usage found: $usage")
end
return ModuleUsage(head, modpath::Vector{Any}, name::Union{Nothing,Symbol}, alias::Union{Nothing,Symbol})
end

function form_module_usage(moduleusage::ModuleUsage)
(; head, modpath, name, alias) = moduleusage
if isa(alias, Symbol)
if isa(name, Symbol)
return form_module_usage_alias(head, modpath, name, alias)
else
@assert isnothing(name) lazy"unexpected pattern match happened: $usage"
return form_module_import_alias(modpath, alias)
end
elseif isa(name, Symbol)
return form_module_usage_specific(head, modpath, name)
end
return form_module_usage(head, modpath)
end

# using A.B.C
form_module_usage(head::Symbol, modpath::Vector{Any}) =
Expr(head, Expr(:., modpath...))
Expand All @@ -880,6 +911,9 @@ form_module_usage_specific(head::Symbol, modpath::Vector{Any}, name::Symbol) =
# using A.B.C: abc as abc′
form_module_usage_alias(head::Symbol, modpath::Vector{Any}, name::Symbol, alias::Symbol) =
Expr(head, Expr(:(:), Expr(:., modpath...), Expr(:as, Expr(:., name), alias)))
# import A.B.C as abc
form_module_import_alias(modpath::Vector{Any}, alias::Symbol) =
Expr(:import, Expr(:as, Expr(:., modpath...), alias))

# if virtualized, replace self references of `actualmod` with `virtualmod` (as is)
fix_self_references!(::Nothing, @nospecialize(x)) = x
Expand Down Expand Up @@ -914,30 +948,10 @@ function fix_self_references!((actualmod, virtualmod)::Actual2Virtual, @nospecia
if isexpr(usage, :export)
return usage
end
modpath = name = alias = nothing
if @capture(usage, import modpath__)
head = :import
elseif @capture(usage, using modpath__)
head = :using
elseif @capture(usage, import modpath__: name_)
head = :import
elseif @capture(usage, using modpath__: name_)
head = :using
elseif @capture(usage, import modpath__: name_ as alias_)
head = :import
elseif @capture(usage, using modpath__: name_ as alias_)
head = :using
else
error(lazy"unexpected module usage found: $usage")
end
modpath = modpath::Vector{Any}
any_self(modpath) || return usage
if isa(alias, Symbol) && isa(name, Symbol)
return form_module_usage_alias(head, fix_self(modpath), name, alias)
elseif isa(name, Symbol)
return form_module_usage_specific(head, fix_self(modpath), name)
end
return form_module_usage(head, fix_self(modpath))
module_usage = pattern_match_module_usage(usage)
any_self(module_usage.modpath) || return usage
fixed_module_usage = ModuleUsage(module_usage; modpath = fix_self(module_usage.modpath))
return form_module_usage(fixed_module_usage)
end

function fix_self_reference(usage::Expr)
Expand Down
39 changes: 34 additions & 5 deletions test/toplevel/test_virtualprocess.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2183,6 +2183,7 @@ end
makebox() = Core.Box()
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("ImportBase" => quote
import Base: show
Expand All @@ -2208,12 +2209,14 @@ end
callfunc1() = func1()
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("UsingAlias" => quote
using PkgAnalysisDep: func1 as func
callfunc1() = func()
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("UsingInner" => quote
using PkgAnalysisDep.Inner
Expand Down Expand Up @@ -2253,18 +2256,35 @@ end
callfunc1() = PkgAnalysisDep.func1()
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("ImportAlias" => quote
import PkgAnalysisDep as PAD
callfunc1() = PAD.func1()
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("ImportInnerAlias" => quote
import PkgAnalysisDep.Inner as PADI
callfunc3() = PADI.func3()
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("ImportSpecific" => quote
import PkgAnalysisDep: func1
callfunc1() = func1()
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("ImportAlias" => quote
import PkgAnalysisDep: func1 as func
callfunc1() = func()
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("ImportInner" => quote
import PkgAnalysisDep.Inner
Expand All @@ -2282,6 +2302,7 @@ end
end
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("ImportBlock" => quote
global truecond::Bool = true
Expand All @@ -2291,6 +2312,7 @@ end
end
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end

test_report_package("RelativeDependency" => quote
Expand Down Expand Up @@ -2345,6 +2367,7 @@ end
Pkg.add("Preferences"; io=devnull)
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end

test_report_package("SelfImport1" => quote
Expand All @@ -2357,6 +2380,7 @@ end
call_overload(x::Number) = overload(x)
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end

test_report_package("SelfImport2" => quote
Expand All @@ -2374,6 +2398,7 @@ end
call_overload(x::Number) = overload(x)
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end

test_report_package("SelfImport5" => quote
Expand All @@ -2394,22 +2419,25 @@ end
call_overload(x::Number) = overload(x)
end) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end

# ignore_missing_comparison should be turned on by default for `report_package`
test_report_package("Issue542" => quote
struct Issue542 end
isa542(x) = x == Issue542() ? true : false
test_report_package("Issue542_1" => quote
struct Issue542Typ end
isa542(x) = x == Issue542Typ() ? true : false
end;
base_setup=()->nothing) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
test_report_package("Issue542_2" => quote
struct Issue542 end
isa542(x) = x == Issue542() ? true : false
struct Issue542Typ end
isa542(x) = x == Issue542Typ() ? true : false
end;
base_setup=()->nothing,
ignore_missing_comparison=false) do res
@test isempty(res.res.toplevel_error_reports)
@test isa(only(res.res.inference_error_reports), NonBooleanCondErrorReport)
end

Expand All @@ -2418,6 +2446,7 @@ end
reducer(a::Vector{String}) = maximum(length, a)
end;
base_setup=()->nothing) do res
@test isempty(res.res.toplevel_error_reports)
@test isempty(res.res.inference_error_reports)
end
end
Expand Down

0 comments on commit efea99b

Please sign in to comment.