Perhaps that's not its strictly-intended usage, but I've found it useful to temporarily pepper my code with @inferred to catch type-instabilities. Unfortunately, it seems that the output of @inferred can be type-unstable (0.6, rc2), which is an issue for checking the type-stability of heterogeneous tree traversal algorithms.
struct AA{A}
a::A
end
struct CC{A}
a::A
end
my_construct(::Type{AA}, a) = 1
my_construct(::Type{CC}, a) = 1.0
foo(x) = @inferred my_construct(CC, x.a)
@inferred foo(CC(2)) #return type Float64 does not match inferred return type Union{Float64, Int64}
my_construct(::Type{Complex}, a) = 1
my_construct(::Type{Array}, a) = 1.0
function foo(x)
args = (Array, x)
my_construct(args...)
end
@code_warntype foo(1)
@inferred is not really designed for this; for this use I think we'd want something that's a no-op at run time but that throws an error at compile time if the wrapped expression couldn't be precisely inferred.
That would be great!
aka #10980 ?
julia> function foo(x)
args = (Array, x)
args[1]
end
foo (generic function with 1 method)
julia> @code_warntype foo(1)
Variables:
#self#::#foo
x::Int64
args::Any
Body:
begin
SSAValue(0) = Main.Array
SSAValue(1) = x::Int64
#= line 3 =#
return SSAValue(0)
end::UnionAll
julia> function foo(x)
args = (Array, 1)
args[1]
end
foo (generic function with 1 method)
julia> @code_warntype foo(1)
Variables:
#self#::#foo
x::Int64
args::Any
Body:
begin
SSAValue(0) = Main.Array
#= line 3 =#
return SSAValue(0)
end::Type{Array}
So unless args can be inferred as Const, args[1] is inferred as typeof(Array) == UnionAll instead of Type{Array}. That's because of the check in this line. Unfortunately, the reason it was introduced back in afd4eb038dcd9fa3e512509f4c332a9e7763ba59 is anything but clear to me. Do we actually still need that?
EDIT:
We do:
julia> typeof((Array,1))
Tuple{UnionAll,Int64}
Inferring that as Type{Tuple{Type{Array}, Int64} is obviously a bad idea.
This is fixed.
Most helpful comment
aka #10980 ?