Skip to content

Commit

Permalink
fix #20704, pure annotation should not skip method errors
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson committed Feb 22, 2017
1 parent 474d05d commit a441a50
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 24 deletions.
59 changes: 35 additions & 24 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ mutable struct InferenceState
vararg_type = rewrap(vararg_type, linfo.specTypes)
end
s_types[1][la] = VarState(vararg_type, false)
src.slottypes[la] = widenconst(vararg_type)
src.slottypes[la] = vararg_type
la -= 1
end
end
Expand Down Expand Up @@ -220,11 +220,11 @@ mutable struct InferenceState
end
i == laty && (lastatype = atyp)
s_types[1][i] = VarState(atyp, false)
src.slottypes[i] = widenconst(atyp)
src.slottypes[i] = atyp
end
for i = (atail + 1):la
s_types[1][i] = VarState(lastatype, false)
src.slottypes[i] = widenconst(lastatype)
src.slottypes[i] = lastatype
end
else
@assert la == 0 # wrong number of arguments
Expand Down Expand Up @@ -1544,13 +1544,18 @@ function return_type_tfunc(argtypes::ANY, vtypes::VarTable, sv::InferenceState)
return NF
end

function pure_eval_call(f::ANY, argtypes::ANY, atype::ANY, vtypes::VarTable, sv::InferenceState)
function are_args_const(argtypes::ANY)
for i = 2:length(argtypes)
a = argtypes[i]
if !(isa(a,Const) || isconstType(a))
return false
end
end
return true
end

function pure_eval_call(f::ANY, argtypes::ANY, atype::ANY, vtypes::VarTable, sv::InferenceState)
are_args_const(argtypes) || return false

min_valid = UInt[typemin(UInt)]
max_valid = UInt[typemax(UInt)]
Expand Down Expand Up @@ -2927,28 +2932,33 @@ function optimize(me::InferenceState)

if isa(me.bestguess, Const) || isconstType(me.bestguess)
me.const_ret = true
ispure = me.src.pure
if !ispure && length(me.src.code) < 10
ispure = true
proven_pure = false
# must be proven pure to use const_api; otherwise we might skip throwing errors
# (issue #20704)
# TODO: Improve this analysis; if a function is marked @pure we should really
# only care about certain errors (e.g. method errors and type errors).
if length(me.src.code) < 10
proven_pure = true
for stmt in me.src.code
if !statement_effect_free(stmt, me.src, me.mod)
ispure = false
proven_pure = false
break
end
end
if ispure
if proven_pure
for fl in me.src.slotflags
if (fl & Slot_UsedUndef) != 0
ispure = false
proven_pure = false
break
end
end
end
end
me.src.pure = ispure
if proven_pure
me.src.pure = true
end

do_coverage = coverage_enabled()
if ispure && !do_coverage
if proven_pure && !coverage_enabled()
# use constant calling convention
# Do not emit `jlcall_api == 2` if coverage is enabled
# so that we don't need to add coverage support
Expand Down Expand Up @@ -3079,7 +3089,7 @@ function annotate_slot_load!(e::Expr, vtypes::VarTable, sv::InferenceState, unde
undefs[id] = true
end
# add type annotations where needed
if !(sv.src.slottypes[id] <: vt)
if !(sv.src.slottypes[id] vt)
e.args[i] = TypedSlot(id, vt)
end
end
Expand Down Expand Up @@ -3222,6 +3232,7 @@ end
# we also need to preserve the type for any untyped load of a DataType
# since codegen optimizations of functions like `is` will depend on knowing it
function widen_slot_type(ty::ANY, untypedload::Bool)
ty = widenconst(ty)
if isa(ty, DataType)
if untypedload || isbits(ty) || isdefined(ty, :instance)
return ty
Expand Down Expand Up @@ -3767,23 +3778,23 @@ function inlineable(f::ANY, ft::ANY, e::Expr, atypes::Vector{Any}, sv::Inference
atype_unlimited, method.sig)
methsp = methsp::SimpleVector
end
# check whether call can be inlined to just a quoted constant value
if isa(f, widenconst(ft)) && !method.isstaged && (method.source.pure || f === return_type)
if isconstType(e.typ)
return inline_as_constant(e.typ.parameters[1], argexprs, sv,
invoke_data)
elseif isa(e.typ,Const)
return inline_as_constant(e.typ.val, argexprs, sv,
invoke_data)
end
end

methsig = method.sig
if !(atype <: metharg)
return invoke_NF(argexprs, e.typ, atypes, sv, atype_unlimited,
invoke_data)
end

# check whether call can be inlined to just a quoted constant value
if isa(f, widenconst(ft)) && !method.isstaged && (method.source.pure || f === return_type) &&
are_args_const(atypes)
if isconstType(e.typ)
return inline_as_constant(e.typ.parameters[1], argexprs, sv, invoke_data)
elseif isa(e.typ,Const)
return inline_as_constant(e.typ.val, argexprs, sv, invoke_data)
end
end

argexprs0 = argexprs
na = Int(method.nargs)
# check for vararg function
Expand Down
18 changes: 18 additions & 0 deletions test/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -648,3 +648,21 @@ let A = 1:2, z = zip(A, A, A, A, A, A, A, A, A, A, A, A)
@test z isa Core.Inference.limit_type_depth(typeof(z), 0)
@test start(z) == (1, (1, (1, (1, (1, (1, (1, (1, (1, (1, (1, 1)))))))))))
end

# issue #20704
f20704(::Int) = 1
Base.@pure b20704(x::ANY) = f20704(x)
@test b20704(42) === 1
@test_throws MethodError b20704(42.0)

bb20704() = b20704(Any[1.0][1])
@test_throws MethodError bb20704()

v20704() = Val{b20704(Any[1.0][1])}
@test_throws MethodError v20704()
@test Base.return_types(v20704, ()) == Any[Type{Val{1}}]

Base.@pure g20704(::Int) = 1
h20704(x::ANY) = g20704(x)
@test g20704(1) === 1
@test_throws MethodError h20704(1.2)

0 comments on commit a441a50

Please sign in to comment.