Skip to content

Commit

Permalink
add some unnecessary MethodError restrictions for Type (JuliaLang#43087)
Browse files Browse the repository at this point in the history
The previous `@nospecialize(::Type)` dispatch signatures actually caused the following kinds of dynamic dispatches:
```julia
julia> using JET

julia> report_opt((Vector{Any},)) do ts
           isbitstype(ts[1])
       end
═════ 1 possible error found ═════
┌ @ REPL[3]:2 Main.isbitstype(%1)
│ runtime dispatch detected: Main.isbitstype(%1::Any)
└─────────────
```

This commit also adds an overload of `emptymutable(::IdSet)`, which
eliminates the dynamic dispatch below:
```julia
julia> report_opt((Base.IdSet{Any}, Base.IdSet{Any}); annotate_types=true) do s1, s2
           s1 ∪ s2
       end
═════ 2 possible errors found ═════
┌ @ REPL[3]:2 Main.∪(s1::Base.IdSet{Any}, s2::Base.IdSet{Any})
│┌ @ abstractset.jl:48 Base.union!(Core.tuple(Base.emptymutable(s::Base.IdSet{Any}, Base.promote_eltype(Core.tuple(s::Base.IdSet{Any})::Tuple{Base.IdSet{Any}}, sets::Tuple{Base.IdSet{Any}}...)::Type{Any})::Set{Any}, s::Base.IdSet{Any})::Tuple{Set{Any}, Base.IdSet{Any}}, sets::Tuple{Base.IdSet{Any}}...)
││┌ @ abstractset.jl:76 Base.union!(s::Set{Any}, x::Base.IdSet{Any})
│││┌ @ abstractset.jl:93 Base.sizehint!(s::Set{Any}, Base.+(Base.length(s::Set{Any})::Int64, Core.typeassert(Base.Int(Base.length(itr::Base.IdSet{Any})::Int64)::Int64, Base.Int)::Int64)::Int64)
││││┌ @ set.jl:84 Base.sizehint!(Base.getproperty(s::Set{Any}, :dict::Symbol)::Dict{Any, Nothing}, newsz::Int64)
│││││┌ @ dict.jl:244 Base.rehash!(d::Dict{Any, Nothing}, newsz::Int64)
││││││┌ @ dict.jl:203 Base.hashindex(%231::Any, %20::Int64)
│││││││ runtime dispatch detected: Base.hashindex(%231::Any, %20::Int64)
││││││└───────────────
│││┌ @ abstractset.jl:95 Base.push!(s::Set{Any}, %62::Any)
││││ runtime dispatch detected: Base.push!(s::Set{Any}, %62::Any)
│││└─────────────────────
```
  • Loading branch information
aviatesk authored and LilithHafner committed Feb 22, 2022
1 parent fa5cbb7 commit 24a5f6f
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 8 deletions.
1 change: 1 addition & 0 deletions base/idset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ IdSet{T}(itr) where {T} = union!(IdSet{T}(), itr)
IdSet() = IdSet{Any}()

copymutable(s::IdSet) = typeof(s)(s)
emptymutable(s::IdSet{T}, ::Type{U}=T) where {T,U} = IdSet{U}()
copy(s::IdSet) = typeof(s)(s)

isempty(s::IdSet) = isempty(s.dict)
Expand Down
16 changes: 8 additions & 8 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ Determine whether type `T` was declared as a mutable type
!!! compat "Julia 1.7"
This function requires at least Julia 1.7.
"""
function ismutabletype(@nospecialize(t::Type))
function ismutabletype(@nospecialize t)
t = unwrap_unionall(t)
# TODO: what to do for `Union`?
return isa(t, DataType) && t.name.flags & 0x2 == 0x2
Expand All @@ -496,7 +496,7 @@ end
Determine whether type `T` was declared as a struct type
(i.e. using the `struct` or `mutable struct` keyword).
"""
function isstructtype(@nospecialize(t::Type))
function isstructtype(@nospecialize t)
@_pure_meta
t = unwrap_unionall(t)
# TODO: what to do for `Union`?
Expand All @@ -511,7 +511,7 @@ end
Determine whether type `T` was declared as a primitive type
(i.e. using the `primitive` keyword).
"""
function isprimitivetype(@nospecialize(t::Type))
function isprimitivetype(@nospecialize t)
@_pure_meta
t = unwrap_unionall(t)
# TODO: what to do for `Union`?
Expand Down Expand Up @@ -543,7 +543,7 @@ julia> isbitstype(Complex)
false
```
"""
isbitstype(@nospecialize(t::Type)) = (@_pure_meta; isa(t, DataType) && (t.flags & 0x8) == 0x8)
isbitstype(@nospecialize t) = (@_pure_meta; isa(t, DataType) && (t.flags & 0x8) == 0x8)

"""
isbits(x)
Expand Down Expand Up @@ -1199,7 +1199,7 @@ end
Similar to [`code_typed`](@ref), except the argument is a tuple type describing
a full signature to query.
"""
function code_typed_by_type(@nospecialize(tt::Type);
function code_typed_by_type(@nospecialize(tt#=::Type=#);
optimize=true,
debuginfo::Symbol=:default,
world = get_world_counter(),
Expand Down Expand Up @@ -1276,7 +1276,7 @@ function print_statement_costs(io::IO, @nospecialize(f), @nospecialize(t); kwarg
print_statement_costs(io, tt; kwargs...)
end

function print_statement_costs(io::IO, @nospecialize(tt::Type);
function print_statement_costs(io::IO, @nospecialize(tt#=::Type=#);
world = get_world_counter(),
interp = Core.Compiler.NativeInterpreter(world))
matches = _methods_by_ftype(tt, -1, world)
Expand Down Expand Up @@ -1306,7 +1306,7 @@ end

print_statement_costs(args...; kwargs...) = print_statement_costs(stdout, args...; kwargs...)

function _which(@nospecialize(tt::Type), world=get_world_counter())
function _which(@nospecialize(tt#=::Type=#), world=get_world_counter())
min_valid = RefValue{UInt}(typemin(UInt))
max_valid = RefValue{UInt}(typemax(UInt))
match = ccall(:jl_gf_invoke_lookup_worlds, Any,
Expand Down Expand Up @@ -1341,7 +1341,7 @@ end
Returns the method that would be called by the given type signature (as a tuple type).
"""
function which(@nospecialize(tt::Type))
function which(@nospecialize(tt#=::Type=#))
return _which(tt).method
end

Expand Down

0 comments on commit 24a5f6f

Please sign in to comment.