JuliaLang / julia

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

Subtyping distributivity fails with diagonal typevar #48338

Open topolarity opened 1 year ago

topolarity commented 1 year ago

I believe this should report true:

julia> (Tuple{T,T} where T<:Union{Int32,Int64}) == Union{Tuple{Int32,Int32},Tuple{Int64,Int64}}
false

Interestingly, making the union larger does make it distribute eventually:

julia> A = Union{Tuple{T,T} where T<:Union{Int32,Int64},Tuple{Int32,Int64},Tuple{Int64,Int32}};

julia> B = Tuple{Union{Int32,Int64},Union{Int32,Int64}};

julia> A == B
true

Reproduces on Julia 1.8 (and also 1.9 and master):

julia> versioninfo()
Julia Version 1.8.5
Commit 17cfb8e65ea (2023-01-08 06:45 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin21.4.0)
  CPU: 8 × Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-13.0.1 (ORCJIT, icelake-client)
  Threads: 1 on 8 virtual cores
topolarity commented 1 year ago

Something similar with T in an invariant position:

julia> supertype(Int64)
Signed

julia> (Ref{T} where Int64<:T<:Signed) == Union{Ref{Int64},Ref{Signed}}
false

Or combining both of these quirks:

julia> (Tuple{T,T} where Int64<:T<:Any) == Tuple{Int64, Int64}
false

These should probably also be true, since T >: lb closes the UnionAll range (if I've thought it through correctly)

Edit: There are also examples without lower bounds:

julia> Union{Ref{Union{Int,String}}, Ref{<:Int}, Ref{<:String}} == Ref{<:Union{Int,String}}
false
Seelengrab commented 1 year ago

UnionAlls and Unions are not equal, even if their effective extent may be, no? This is the same case, and I wouldn't necessarily expect them to be equal, since one is a type variable and the other a type:

julia> (Ref{T} where T<:Int) == Ref{Int}
false