Skip to content

kill isleaftype #25496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -827,10 +827,10 @@ Deprecated or removed
been deprecated due to inconsistency with linear algebra. Use `.+` and `.-` for these operations
instead ([#22880], [#22932]).

* `isleaftype` is deprecated in favor of a simpler predicate `isconcrete`. Concrete types are
those that might equal `typeof(x)` for some `x`; `isleaftype` includes some types for which
this is not true. If you are certain you need the old behavior, it is temporarily available
as `Base._isleaftype` ([#17086]).
* `isleaftype` is deprecated in favor of the simpler predicates `isconcretetype` and `isdispatchtuple`.
Concrete types are those that might equal `typeof(x)` for some `x`;
`isleaftype` included some types for which this is not true. Those are now categorized more precisely
as "dispatch tuple types" and "!has_free_typevars" (not exported). ([#17086], [#25496])

* `contains(eq, itr, item)` is deprecated in favor of `any` with a predicate ([#23716]).

Expand Down
2 changes: 1 addition & 1 deletion base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1985,7 +1985,7 @@ function hash(a::AbstractArray{T}, h::UInt) where T
# to a range with more than two elements because more extreme values
# cannot be represented. We must still hash the two first values as a
# range since they can always be considered as such (in a wider type)
if isconcrete(T)
if isconcretetype(T)
try
step = x2 - x1
catch err
Expand Down
2 changes: 1 addition & 1 deletion base/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ julia> string.(("one","two","three","four"), ": ", 1:4)
const NonleafHandlingTypes = Union{DefaultArrayStyle,ArrayConflict,VectorStyle,MatrixStyle}

@inline function broadcast(f, s::NonleafHandlingTypes, ::Type{ElType}, inds::Indices, As...) where ElType
if !Base._isleaftype(ElType)
if !Base.isconcretetype(ElType)
return broadcast_nonleaf(f, s, ElType, inds, As...)
end
dest = broadcast_similar(f, s, ElType, inds, As...)
Expand Down
45 changes: 22 additions & 23 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,10 @@ function abstract_call_method_with_const_args(@nospecialize(f), argtypes::Vector
haveconst = false
for i in 1:nargs
a = argtypes[i]
if isa(a, Const) && !isdefined(typeof(a.val), :instance)
if !isleaftype(a.val) # alternately: !isa(a.val, DataType) || !isconstType(Type{a.val})
# have new information from argtypes that wasn't available from the signature
haveconst = true
break
end
if isa(a, Const) && !isdefined(typeof(a.val), :instance) && !(isa(a.val, Type) && issingletontype(a.val))
# have new information from argtypes that wasn't available from the signature
haveconst = true
break
end
end
haveconst || return Any
Expand Down Expand Up @@ -378,11 +376,13 @@ end

# do apply(af, fargs...), where af is a function value
function abstract_apply(@nospecialize(aft), fargs::Vector{Any}, aargtypes::Vector{Any}, vtypes::VarTable, sv::InferenceState)
if !isa(aft, Const) && !isconstType(aft)
if !(isleaftype(aft) || aft <: Type) || (aft <: Builtin) || (aft <: IntrinsicFunction)
if !isa(aft, Const) && (!isType(aft) || has_free_typevars(aft))
if !isconcretetype(aft) || (aft <: Builtin)
# non-constant function of unknown type: bail now,
# since it seems unlikely that abstract_call will be able to do any better after splitting
# this also ensures we don't call abstract_call_gf_by_type below on an IntrinsicFunction or Builtin
return Any
end
# non-constant function, but type is known
end
res = Union{}
nargs = length(fargs)
Expand All @@ -394,7 +394,7 @@ function abstract_apply(@nospecialize(aft), fargs::Vector{Any}, aargtypes::Vecto
for ti in (splitunions ? uniontypes(aargtypes[i]) : Any[aargtypes[i]])
cti = precise_container_type(fargs[i], ti, vtypes, sv)
for ct in ctypes
if !isempty(ct) && isvarargtype(ct[end])
if isvarargtype(ct[end])
tail = tuple_tail_elem(unwrapva(ct[end]), cti)
push!(ctypes´, push!(ct[1:(end - 1)], tail))
else
Expand Down Expand Up @@ -672,23 +672,22 @@ function abstract_eval_call(e::Expr, vtypes::VarTable, sv::InferenceState)
ft = argtypes[1]
if isa(ft, Const)
f = ft.val
elseif isconstType(ft)
f = ft.parameters[1]
elseif isa(ft, DataType) && isdefined(ft, :instance)
f = ft.instance
else
if isType(ft) && isleaftype(ft.parameters[1])
f = ft.parameters[1]
elseif isleaftype(ft) && isdefined(ft, :instance)
f = ft.instance
else
for i = 2:(length(argtypes)-1)
if isvarargtype(argtypes[i])
return Any
end
end
# non-constant function, but type is known
if (isleaftype(ft) || ft <: Type) && !(ft <: Builtin) && !(ft <: IntrinsicFunction)
return abstract_call_gf_by_type(nothing, argtypes, argtypes_to_type(argtypes), sv)
for i = 2:(length(argtypes) - 1)
if isvarargtype(argtypes[i])
return Any
end
end
# non-constant function, but the number of arguments is known
# and the ft is not a Builtin or IntrinsicFunction
if typeintersect(widenconst(ft), Builtin) != Union{}
return Any
end
return abstract_call_gf_by_type(nothing, argtypes, argtypes_to_type(argtypes), sv)
end
return abstract_call(f, e.args, argtypes, vtypes, sv)
end
Expand Down
2 changes: 0 additions & 2 deletions base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ include("docs/core.jl")
inlining_enabled() = (JLOptions().can_inline == 1)
coverage_enabled() = (JLOptions().code_coverage != 0)

const isleaftype = _isleaftype

include("compiler/utilities.jl")
include("compiler/validation.jl")

Expand Down
2 changes: 1 addition & 1 deletion base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ mutable struct InferenceState
at = (i > nargs) ? Bottom : argtypes[i]
if !toplevel && linfo.def.isva && i == nargs
if !(at == Tuple) # would just be a no-op
vararg_type_container = limit_tuple_depth(params, unwrap_unionall(at)) # TODO: should be limiting tuple depth much earlier than here
vararg_type_container = unwrap_unionall(at)
vararg_type = tuple_tfunc(vararg_type_container) # returns a Const object, if applicable
at = rewrap(vararg_type, linfo.specTypes)
end
Expand Down
62 changes: 33 additions & 29 deletions base/compiler/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -827,8 +827,8 @@ function effect_free(@nospecialize(e), src::CodeInfo, mod::Module, allow_volatil
return true
end
if head === :static_parameter
# if we aren't certain about the type, it might be an UndefVarError at runtime
return (isa(e.typ, DataType) && isleaftype(e.typ)) || isa(e.typ, Const)
# if we aren't certain enough about the type, it might be an UndefVarError at runtime
return isa(e.typ, Const) || issingletontype(widenconst(e.typ))
end
if e.typ === Bottom
return false
Expand All @@ -841,17 +841,17 @@ function effect_free(@nospecialize(e), src::CodeInfo, mod::Module, allow_volatil
return false
elseif is_known_call(e, getfield, src, mod)
nargs = length(ea)
(2 < nargs < 5) || return false
(3 < nargs < 4) || return false
et = exprtype(e, src, mod)
if !isa(et, Const) && !(isType(et) && isleaftype(et))
# TODO: check ninitialized
if !isa(et, Const) && !isconstType(et)
# first argument must be immutable to ensure e is affect_free
a = ea[2]
typ = widenconst(exprtype(a, src, mod))
if isconstType(typ)
if Const(:uid) ⊑ exprtype(ea[3], src, mod)
return false # DataType uid field can change
end
elseif typ !== SimpleVector && (!isa(typ, DataType) || typ.mutable || typ.abstract)
typ = unwrap_unionall(widenconst(exprtype(a, src, mod)))
if isType(typ)
# all fields of subtypes of Type are effect-free
# (including the non-inferrable uid field)
elseif !isa(typ, DataType) || typ.abstract || (typ.mutable && length(typ.types) > 0)
return false
end
end
Expand All @@ -874,7 +874,8 @@ function effect_free(@nospecialize(e), src::CodeInfo, mod::Module, allow_volatil
# `Expr(:new)` of unknown type could raise arbitrary TypeError.
typ, isexact = instanceof_tfunc(typ)
isexact || return false
(isleaftype(typ) && !iskindtype(typ)) || return false
isconcretetype(typ) || return false
!iskindtype(typ) || return false
typ = typ::DataType
if !allow_volatile && typ.mutable
return false
Expand Down Expand Up @@ -1086,11 +1087,11 @@ function inlineable(@nospecialize(f), @nospecialize(ft), e::Expr, atypes::Vector
sv::OptimizationState)
argexprs = e.args

if (f === typeassert || ft ⊑ typeof(typeassert)) && length(atypes)==3
if (f === typeassert || ft ⊑ typeof(typeassert)) && length(atypes) == 3
# typeassert(x::S, T) => x, when S<:T
a3 = atypes[3]
if (isType(a3) && isleaftype(a3) && atypes[2] ⊑ a3.parameters[1]) ||
(isa(a3,Const) && isa(a3.val,Type) && atypes[2] ⊑ a3.val)
if (isType(a3) && !has_free_typevars(a3) && atypes[2] ⊑ a3.parameters[1]) ||
(isa(a3, Const) && isa(a3.val, Type) && atypes[2] ⊑ a3.val)
return (argexprs[2], ())
end
end
Expand Down Expand Up @@ -1119,7 +1120,9 @@ function inlineable(@nospecialize(f), @nospecialize(ft), e::Expr, atypes::Vector
if f === Core.invoke && length(atypes) >= 3
ft = widenconst(atypes[2])
invoke_tt = widenconst(atypes[3])
if !isleaftype(ft) || !isleaftype(invoke_tt) || !isType(invoke_tt)
if !(isconcretetype(ft) || ft <: Type) || !isType(invoke_tt) ||
has_free_typevars(invoke_tt) || has_free_typevars(ft) || (ft <: Builtin)
# TODO: this is really aggressive at preventing inlining of closures. maybe drop `isconcretetype` requirement?
return NOT_FOUND
end
if !(isa(invoke_tt.parameters[1], Type) &&
Expand Down Expand Up @@ -1282,12 +1285,10 @@ function inlineable(@nospecialize(f), @nospecialize(ft), e::Expr, atypes::Vector
haveconst = false
for i in 1:length(atypes)
a = atypes[i]
if isa(a, Const) && !isdefined(typeof(a.val), :instance)
if !isleaftype(a.val) # alternately: !isa(a.val, DataType) || !isconstType(Type{a.val})
# have new information from argtypes that wasn't available from the signature
haveconst = true
break
end
if isa(a, Const) && !isdefined(typeof(a.val), :instance) && !(isa(a.val, Type) && issingletontype(a.val))
# have new information from argtypes that wasn't available from the signature
haveconst = true
break
end
end
if haveconst
Expand Down Expand Up @@ -1549,8 +1550,9 @@ end

# saturating sum (inputs are nonnegative), prevents overflow with typemax(Int) below
plus_saturate(x, y) = max(x, y, x+y)

# known return type
isknowntype(T) = (T == Union{}) || isleaftype(T)
isknowntype(@nospecialize T) = (T == Union{}) || isconcretetype(T)

function statement_cost(ex::Expr, line::Int, src::CodeInfo, mod::Module, params::Params)
head = ex.head
Expand Down Expand Up @@ -1781,7 +1783,8 @@ function inline_call(e::Expr, sv::OptimizationState, stmts::Vector{Any}, boundsc
ft = Bool
else
f = nothing
if !( isleaftype(ft) || ft<:Type )
if !(isconcretetype(ft) || (widenconst(ft) <: Type)) || has_free_typevars(ft)
# TODO: this is really aggressive at preventing inlining of closures. maybe drop `isconcretetype` requirement?
return e
end
end
Expand Down Expand Up @@ -1938,7 +1941,8 @@ function inline_call(e::Expr, sv::OptimizationState, stmts::Vector{Any}, boundsc
ft = Bool
else
f = nothing
if !( isleaftype(ft) || ft<:Type )
if !(isconcretetype(ft) || (widenconst(ft) <: Type)) || has_free_typevars(ft)
# TODO: this is really aggressive at preventing inlining of closures. maybe drop `isconcretetype` requirement?
return e
end
end
Expand Down Expand Up @@ -2754,15 +2758,15 @@ end

function split_disjoint_assign!(ctx::AllocOptContext, info, key)
key.second && return false
isleaftype(ctx.sv.src.slottypes[key.first]) && return false
isdispatchelem(widenconst(ctx.sv.src.slottypes[key.first])) && return false # no splitting can be necessary
alltypes = IdDict()
ndefs = length(info.defs)
deftypes = Vector{Any}(uninitialized, ndefs)
for i in 1:ndefs
def = info.defs[i]
defex = (def.assign::Expr).args[2]
rhstyp = widenconst(exprtype(defex, ctx.sv.src, ctx.sv.mod))
isleaftype(rhstyp) || return false
isdispatchelem(rhstyp) || return false
alltypes[rhstyp] = nothing
deftypes[i] = rhstyp
end
Expand All @@ -2772,7 +2776,7 @@ function split_disjoint_assign!(ctx::AllocOptContext, info, key)
slot = usex.args[use.exidx]
if isa(slot, TypedSlot)
usetyp = widenconst(slot.typ)
if isleaftype(usetyp)
if isdispatchelem(usetyp)
alltypes[usetyp] = nothing
continue
end
Expand Down Expand Up @@ -2827,7 +2831,7 @@ function split_disjoint_assign!(ctx::AllocOptContext, info, key)
slot = usex.args[use.exidx]
if isa(slot, TypedSlot)
usetyp = widenconst(slot.typ)
if isleaftype(usetyp)
if isdispatchelem(usetyp)
usetyp = widenconst(slot.typ)
new_slot = alltypes[usetyp]
if !isa(new_slot, SlotNumber)
Expand Down Expand Up @@ -2997,7 +3001,7 @@ function split_struct_alloc!(ctx::AllocOptContext, info, key)
elseif defex.head === :new
typ = widenconst(exprtype(defex, ctx.sv.src, ctx.sv.mod))
# typ <: Tuple shouldn't happen but just in case someone generated invalid AST
if !isa(typ, DataType) || !isleaftype(typ) || typ <: Tuple
if !isa(typ, DataType) || !isdispatchelem(typ) || typ <: Tuple
return false
end
si = structinfo_new(ctx, defex, typ)
Expand Down
4 changes: 1 addition & 3 deletions base/compiler/params.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ struct Params

# parameters limiting large types
MAX_TUPLETYPE_LEN::Int
MAX_TUPLE_DEPTH::Int

# when attempting to inlining _apply, abort the optimization if the tuple
# contains more than this many elements
Expand All @@ -42,13 +41,12 @@ struct Params
inline_tupleret_bonus::Int = 400,
max_methods::Int = 4,
tupletype_len::Int = 15,
tuple_depth::Int = 4,
tuple_splat::Int = 16,
union_splitting::Int = 4,
apply_union_enum::Int = 8)
return new(Vector{InferenceResult}(),
world, inlining, true, false, inline_cost_threshold, inline_nonleaf_penalty,
inline_tupleret_bonus, max_methods, union_splitting, apply_union_enum,
tupletype_len, tuple_depth, tuple_splat)
tupletype_len, tuple_splat)
end
end
Loading