JuliaLang / julia

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

Interpretation of AbstractFloat as a type or constructor depends on usage history #40342

Open timholy opened 3 years ago

timholy commented 3 years ago
tim@diva:~/.julia/dev/IntervalFastMath$ julia -q
julia> struct Wrapper{T}
           x::T
       end

julia> tofloat(x::Wrapper{<:AbstractFloat}) = x
tofloat (generic function with 1 method)

julia> AbstractFloat(x::Wrapper{<:AbstractFloat}) = x
AbstractFloat

julia> exit()
tim@diva:~/.julia/dev/IntervalFastMath$ julia -q
julia> struct Wrapper{T}
           x::T
       end

julia> AbstractFloat(x::Wrapper{<:AbstractFloat}) = x
ERROR: TypeError: in TypeVar, in upper bound, expected Type, got a value of type typeof(AbstractFloat)
Stacktrace:
 [1] TypeVar(n::Symbol, ub::Any)
   @ Core ./boot.jl:382
 [2] top-level scope
   @ REPL[2]:1
vtjnash commented 3 years ago

Are you suggesting we try to identify that it wasn't imported, and suggest that fix (like we would for MethodError)?

timholy commented 3 years ago

That, or bind all the typevars first (though I'm not sure what that error message, if any, will look like). This is also pretty confusing:

julia> struct Wrapper{T}
           x::T
       end

julia> Int(x::Wrapper{Int}) = x
Int (generic function with 1 method)

julia> Int(Wrapper(3))
ERROR: MethodError: no method matching Int(::Wrapper{Int64})
Closest candidates are:
  Int(::Wrapper{Int}) at REPL[2]:1
Stacktrace:
 [1] top-level scope
   @ REPL[3]:1

While there are plenty of hints there about what's happening, it would not be surprising if this stumped most people initially.

JeffBezanson commented 3 years ago

I can see a case for evaluating argument types first, but it feels less "left to right" than what we do now, where the function is introduced first, then a method is added. The example here is certainly confusing though.

vtjnash commented 3 years ago

We might need add another case (for Type constructors) to the existing MethodError text?

julia> sin() = 1
sin (generic function with 1 method)

julia> sin(2)
ERROR: MethodError: no method matching sin(::Int64)
You may have intended to import Base.sin
...