diff --git a/base/inference.jl b/base/inference.jl index 935bb03b7b9d2..a5d34f6ccbd6b 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1966,14 +1966,32 @@ function finish(me::InferenceState) nothing end -function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, undefs) +function record_slot_type!(id, vt::ANY, slottypes) + if vt !== Bottom + otherTy = slottypes[id] + if otherTy === Bottom + slottypes[id] = vt + elseif otherTy !== Any && !typeseq(otherTy, vt) + slottypes[id] = Any + end + end +end + +function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, undefs, pass) if isa(e, Slot) - t = abstract_eval(e, vtypes, sv) - s = vtypes[e.id] - if s.undef - undefs[e.id] = true + id = (e::Slot).id + s = vtypes[id] + vt = widenconst(s.typ) + if pass == 1 + # first pass: find used-undef variables and type-constant variables + if s.undef + undefs[id] = true + end + record_slot_type!(id, vt, sv.linfo.slottypes) + return e end - return t === sv.linfo.slottypes[e.id] ? e : TypedSlot(e.id, t) + # second pass: add type annotations where needed + return vt === sv.linfo.slottypes[id] ? e : TypedSlot(id, vt) end if !isa(e,Expr) @@ -1985,14 +2003,14 @@ function eval_annotate(e::ANY, vtypes::ANY, sv::InferenceState, undefs) if is(head,:static_typeof) || is(head,:line) || is(head,:const) return e elseif is(head,:(=)) - e.args[2] = eval_annotate(e.args[2], vtypes, sv, undefs) + e.args[2] = eval_annotate(e.args[2], vtypes, sv, undefs, pass) return e end i0 = is(head,:method) ? 2 : 1 for i=i0:length(e.args) subex = e.args[i] if !(isa(subex,Number) || isa(subex,AbstractString)) - e.args[i] = eval_annotate(subex, vtypes, sv, undefs) + e.args[i] = eval_annotate(subex, vtypes, sv, undefs, pass) end end return e @@ -2013,38 +2031,31 @@ end # annotate types of all symbols in AST function type_annotate!(linfo::LambdaInfo, states::Array{Any,1}, sv::ANY, nargs) nslots = length(states[1]) - for i = 1:nslots + nargs = linfo.nargs + for i = 1:nargs + linfo.slottypes[i] = widenconst(states[1][i].typ) + end + for i = nargs+1:nslots linfo.slottypes[i] = Bottom end undefs = fill(false, nslots) body = linfo.code::Array{Any,1} nexpr = length(body) - for i=1:nexpr - # identify variables always used as the same type - st_i = states[i] - if st_i !== () - for j = 1:nslots - vt = widenconst(st_i[j].typ) - if vt !== Bottom - otherTy = linfo.slottypes[j] - if otherTy === Bottom - linfo.slottypes[j] = vt - elseif otherTy !== Any && !typeseq(otherTy, vt) - linfo.slottypes[j] = Any - end - end - end - end - end i = 1 optimize = sv.optimize::Bool while i <= nexpr st_i = states[i] + expr = body[i] if st_i !== () # st_i === () => unreached statement (see issue #7836) - body[i] = eval_annotate(body[i], st_i, sv, undefs) + eval_annotate(expr, st_i, sv, undefs, 1) + if isa(expr, Expr) && expr.head == :(=) && i < nexpr && isa(expr.args[1],Slot) && states[i+1] !== () + # record type of assigned slot by looking at the next statement. + # this is needed in case the slot is never used (which makes eval_annotate miss it). + id = expr.args[1].id + record_slot_type!(id, widenconst(states[i+1][id].typ), linfo.slottypes) + end elseif optimize - expr = body[i] if isa(expr, Expr) && expr_cannot_delete(expr::Expr) i += 1 continue @@ -2058,6 +2069,12 @@ function type_annotate!(linfo::LambdaInfo, states::Array{Any,1}, sv::ANY, nargs) end i += 1 end + for i = 1:nexpr + st_i = states[i] + if st_i !== () + body[i] = eval_annotate(body[i], st_i, sv, undefs, 2) + end + end # mark used-undef variables for i = 1:nslots