diff --git a/base/inference.jl b/base/inference.jl index fd45eefcf0d1d..c487302bdce4e 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -1858,7 +1858,7 @@ function without_linenums(a::Array{Any,1}) l end -const _pure_builtins = {tuple, tupleref, tuplelen, fieldtype, apply_type, is, isa, typeof} # known affect-free calls (also effect-free) +const _pure_builtins = {tuple, tupleref, tuplelen, fieldtype, apply_type, is, isa, typeof, typeassert} # known affect-free calls (also effect-free) const _pure_builtins_volatile = {getfield, arrayref} # known effect-free calls (might not be affect-free) function is_pure_builtin(f) @@ -2039,12 +2039,13 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast) # end # end - # when 1 method matches the inferred types, there is still a chance - # of a no-method error at run time, unless the inferred types are a - # subset of the method signature. - if !(atypes <: meth[1]) - return NF + # Undef is a bad type + for ty in atypes + if Undef <: ty + return NF + end end + if !isa(linfo,LambdaStaticData) || meth[3].func.env !== () return NF end @@ -2093,6 +2094,7 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast) args = f_argnames(ast) na = length(args) + isva = false if na>0 && is_rest_arg(ast.args[1][na]) vaname = args[na] len_argexprs = length(argexprs) @@ -2127,6 +2129,7 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast) # construct tuple-forming expression for argument tail vararg = mk_tuplecall(argexprs[na:end]) argexprs = {argexprs[1:(na-1)]..., vararg} + isva = true end end @assert na == length(argexprs) @@ -2163,10 +2166,47 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast) # see if each argument occurs only once in the body expression stmts = {} stmts_free = true # true = all entries of stmts are effect_free - for i=length(args):-1:1 # stmts_free needs to be calculated in reverse-argument order + + methargs = meth[1] + nm = length(methargs) + for i=na:-1:1 # stmts_free needs to be calculated in reverse-argument order a = args[i] aei = argexprs[i] - aeitype = exprtype(aei) + aeitype = argtype = typeintersect(exprtype(aei),Any) # remove Undef + if aeitype == ANY + aeitype = Any + end + if isva + if nm == 0 + methitype = () + elseif i > nm + methitype = methargs[end] + if isvarargtype(methitype) + methitype = (methitype,) + else + methitype = () + end + else + methitype = tuple(methargs[i:end]...) + end + isva = false + else + if i < nm + methitype = methargs[i] + else + methitype = methargs[end] + if isvarargtype(methitype) + methitype = (methitype::Vararg).parameters[1] + else + @assert i==nm + end + end + end + needtypeassert = false + if !(aeitype <: methitype) + needtypeassert = true + aeitype = methitype + end islocal = false # if the argument name is also used as a local variable, # we need to keep it as a variable name @@ -2185,7 +2225,7 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast) # ok for argument to occur more than once if the actual argument # is a symbol or constant, or is not affected by previous statements # that will exist after the inlining pass finishes - affect_free = stmts_free && !islocal # false = previous statements might affect the result of evaluating argument + affect_free = stmts_free && !islocal && !needtypeassert # false = previous statements might affect the result of evaluating argument occ = 0 for j = length(body.args):-1:1 b = body.args[j] @@ -2201,14 +2241,21 @@ function inlineable(f, e::Expr, atypes, sv, enclosing_ast) end end free = effect_free(aei,sv,true) - if ((occ==0 && is(aeitype,None)) || islocal || (occ > 1 && !inline_worthy(aei, occ)) || - (affect_free && !free) || (!affect_free && !effect_free(aei,sv,false))) - if occ != 0 # islocal=true is implied + if ((occ==0 && is(aeitype,None)) || islocal || needtypeassert || (occ > 1 && !inline_worthy(aei, occ)) || + (affect_free && !free) || (!affect_free && !effect_free(aei,sv,false))) + if occ != 0 || needtypeassert # islocal=true is implied # introduce variable for this argument vnew = unique_name(enclosing_ast, ast) add_variable(enclosing_ast, vnew, aeitype, !islocal) - unshift!(stmts, Expr(:(=), vnew, aei)) argexprs[i] = aeitype===Any ? vnew : SymbolNode(vnew,aeitype) + if needtypeassert + vnew2 = unique_name(enclosing_ast, ast) + add_variable(enclosing_ast, vnew2, argtype, true) + push!(stmts, Expr(:(=), vnew, Expr(:call, TopNode(:typeassert), vnew2, aeitype))) + else + vnew2 = vnew + end + unshift!(stmts, Expr(:(=), vnew2, aei)) stmts_free &= free elseif !free && !isType(aeitype) unshift!(stmts, aei)