@@ -29,30 +29,31 @@ test_ambiguities(packages; kwargs...) = _test_ambiguities(aspkgids(packages); kw
2929
3030const ExcludeSpec = Pair{Base. PkgId,String}
3131
32- strnameof (x) = string (x)
33- strnameof (x:: Type ) = string (nameof (x))
34-
35- rootmodule (x) = rootmodule (parentmodule (x))
32+ rootmodule (x:: Type ) = rootmodule (parentmodule (x))
3633rootmodule (m:: Module ) = Base. require (PkgId (m)) # this handles Base/Core well
3734
38- normalize_exclude (x:: Union{Type,Function} ) =
39- Base. PkgId (rootmodule (x)) => join ((fullname (parentmodule (x))... , strnameof (x)), " ." )
40- normalize_exclude (:: Any ) = error (" Only a function and type can be excluded." )
35+ # get the Type associated with x
36+ normalize_exclude_obj (@nospecialize x) = x isa Type ? x : typeof (x)
37+
38+ function normalize_exclude (@nospecialize x)
39+ x = normalize_exclude_obj (x)
40+ return Base. PkgId (rootmodule (x)) => join ((fullname (parentmodule (x))... , string (nameof (x))), " ." )
41+ end
4142
42- function getobj ((pkgid, name):: ExcludeSpec )
43+ function getexclude ((pkgid, name):: ExcludeSpec )
4344 nameparts = Symbol .(split (name, " ." ))
4445 m = Base. require (pkgid)
4546 for name in nameparts
4647 m = getproperty (m, name)
4748 end
48- return m
49+ return normalize_exclude_obj (m)
4950end
5051
5152function normalize_and_check_exclude (exclude:: AbstractVector )
52- exspecs = mapfoldl ( normalize_exclude, push!, exclude, init = ExcludeSpec[])
53- for (spec, obj ) in zip (exspecs, exclude )
54- if getobj (spec ) != = obj
55- error (" Name `$(spec [2 ]) ` is resolved to a different object." )
53+ exspecs = ExcludeSpec[ normalize_exclude (exspec) for exspec in exclude]
54+ for (i, exspec ) in enumerate (exspecs)
55+ if getexclude (exspec ) != = normalize_exclude_obj (exclude[i])
56+ error (" Name `$(exspec [2 ]) ` is resolved to a different object." )
5657 end
5758 end
5859 return exspecs:: Vector{ExcludeSpec}
@@ -154,6 +155,20 @@ function reprpkgid(pkg::PkgId)
154155 return " Base.PkgId(Base.UUID($(repr (uuid. value)) ), $(repr (name)) )"
155156end
156157
158+ # try to extract the called function, or nothing if it is hard to analyze
159+ function trygetft (m:: Method )
160+ sig = Base. unwrap_unionall (m. sig):: DataType
161+ ft = sig. parameters[is_kwcall (sig) ? 3 : 1 ]
162+ ft = Base. unwrap_unionall (ft)
163+ if ft isa DataType && ft. name === Type. body. name
164+ ft = Base. unwrap_unionall (ft. parameters[1 ])
165+ end
166+ if ft isa DataType
167+ return ft. name. wrapper
168+ end
169+ return nothing # cannot exclude signatures with Union
170+ end
171+
157172function test_ambiguities_impl (
158173 packages:: Vector{PkgId} ,
159174 options:: NamedTuple ,
@@ -165,26 +180,9 @@ function test_ambiguities_impl(
165180 ambiguities = detect_ambiguities (modules... ; options... )
166181
167182 if ! isempty (exspecs)
168- exclude_ft = Any[getobj (spec) for spec in exspecs]
169- exclude_sig = Any[]
170- for ft in exclude_ft
171- if ft isa Type
172- push! (exclude_sig, Tuple{ft, Vararg})
173- push! (exclude_sig, Tuple{Core. kwftype (ft), Any, ft, Vararg})
174- ft = Type{<: ft } # alternatively, Type{ft}
175- else
176- ft = typeof (ft)
177- end
178- push! (exclude_sig, Tuple{ft, Vararg})
179- push! (exclude_sig, Tuple{Core. kwftype (ft), Any, ft, Vararg})
180- end
183+ exclude_ft = Any[getexclude (spec) for spec in exspecs] # vector of Type objects
181184 ambiguities = filter (ambiguities) do (m1, m2)
182- for excl in exclude_sig
183- if m1. sig <: excl || m2. sig <: excl
184- return false
185- end
186- end
187- return true
185+ trygetft (m1) ∉ exclude_ft && trygetft (m2) ∉ exclude_ft
188186 end
189187 end
190188
0 commit comments