JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.41k stars 5.45k forks source link

incorrect dispatch trying to print `Union{}` Type #55208

Closed vtjnash closed 2 weeks ago

vtjnash commented 1 month ago

This possibly goes along with the broader prohibition that against overloading show for Type, as this is equivalent to type-piracy in Base. But we should fix the definition or the type-intersection bug that causes this dispatch error:

julia> string((Core.Union{}, true, true, true))
ERROR: TypeError: in typeassert, expected UnionAll, got Type{Union{}}
Stacktrace:
 [1] _show_type(io::IOContext{IOBuffer}, x::Type)
   @ Base ./show.jl:989
 [2] show(io::IOContext{IOBuffer}, x::Type)
   @ Base ./show.jl:970
 [3] show_delim_array(io::IOBuffer, itr::Tuple{Core.TypeofBottom, Bool, Bool, Bool}, op::Char, delim::Char, cl::Char, delim_one::Bool, i1::Int64, n::Int64)
   @ Base ./show.jl:1440
 [4] show_delim_array
   @ ./show.jl:1425 [inlined]
 [5] show
   @ ./show.jl:1458 [inlined]
 [6] print(io::IOBuffer, x::Tuple{Core.TypeofBottom, Bool, Bool, Bool})
   @ Base ./strings/io.jl:35
 [7] print_to_string(xs::Tuple{Core.TypeofBottom, Bool, Bool, Bool})
   @ Base ./strings/io.jl:148
 [8] string(xs::Tuple{Core.TypeofBottom, Bool, Bool, Bool})
   @ Base ./strings/io.jl:189
 [9] top-level scope
   @ REPL[4]:1
JeffBezanson commented 1 month ago

Bisect points to 879f6d482420e181f17af60d361b601cbcc204f9 @Keno

vtjnash commented 1 month ago

Some MWE:

julia> ((x, i) -> begin
       z = (i == 0 ? x[1] : x[i])
       @show z
       return z isa Core.TypeofBottom
       end)((Union{}, 5, 6, 7), 0)
z = 4294967304 # aka 0x0000000100000008, but expect Union{} here
false

julia> ((x, i) -> begin
       z = (i == 0 ? x[1] : x[i])
       typeof(z)
       end)((Union{}, true, true), 0)
ERROR: BoundsError: attempt to access Tuple{Core.TypeofBottom, Bool, Bool} at index [0] # ERR

Note that these segfault or hit an LLVM assertion at least as far back as v0.6


It looks like we used to have

│    %66  = φ (#28 => %37, #66 => %81)::Union{Bool, Type}

but now have the more accurate

│     %72  = φ (#28 => %42, #105 => %87)::Union{Core.TypeofBottom, Bool}                          

that then feeds into this branch

52 ─ %115 = (isa)(%66, Core.TypeofBottom)::Bool
81 ── %152 = (isa)(%72, Core.TypeofBottom)::Bool                                                  

however, codegen seems confused about this since it eventually makes this branch shape

  %12 = and i8 %tindex_phi37, 127                                                                                                                                                                   
  switch i8 %12, label %post_box_union [ ; for Type
    i8 2, label %L129 ; for Bool
    i8 1, label %L154 ; for Union{}
  ]                                                                                                                                                                                                 

but when it allocated the tindex for Union{}, it declared that it was of kind Type and not an instance of the ghost object Core.TypeofBottom

   %tindex_phi52.ph = phi i8 [ -128, %L71 ], [ %58, %guard_exit130 ]
│    ││ %35  = Base.getfield(itr, 1, %34)::Core.TypeofBottom
│     %42  = φ (#17 => %35, #26 => %64)::Union{Core.TypeofBottom, Bool}