Skip to content
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

WIP: Call overload #8008

Closed
wants to merge 13 commits into from
Closed
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
6 changes: 6 additions & 0 deletions base/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ convert(T, x) = convert_default(T, x, convert)
convert(::(), ::()) = ()
convert(::Type{Tuple}, x::Tuple) = x

# fall back to Core.call
call(args...) = Core.call(args...)

# allow convert to be called as if it were a single-argument constructor
# call(T::Type, x) = convert(T, x)

argtail(x, rest...) = rest
tupletail(x::Tuple) = argtail(x...)

Expand Down
12 changes: 7 additions & 5 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ export
Expr, GotoNode, LabelNode, LineNumberNode, QuoteNode, SymbolNode, TopNode,
GetfieldNode, NewvarNode,
# object model functions
apply, fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined,
fieldtype, getfield, setfield!, yieldto, throw, tuple, is, ===, isdefined,
# arraylen, arrayref, arrayset, arraysize, tuplelen, tupleref, convert_default,
# kwcall,
# _apply, kwcall,
# sizeof # not exported, to avoid conflicting with Base.sizeof
# type reflection
issubtype, typeof, isa,
Expand Down Expand Up @@ -168,6 +168,11 @@ export

const (===) = is

# simple convert for use by constructors of types in Core
convert(T, x) = convert_default(T, x, convert)

call(T::Type, arg) = convert(T, arg)

abstract Number
abstract Real <: Number
abstract FloatingPoint <: Real
Expand Down Expand Up @@ -217,9 +222,6 @@ type InterruptException <: Exception end
abstract String
abstract DirectIndexString <: String

# simple convert for use by constructors of types in Core
convert(T, x) = convert_default(T, x, convert)

type SymbolNode
name::Symbol
typ
Expand Down
6 changes: 6 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ const Nothing = Void
export None
const None = Union()

export apply
function apply(f, args...)
depwarn("apply() is deprecated, use `...` instead", :apply)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply(f, x) is deprecated, use f(x...) instead

return Core._apply(call, f, args...)
end

@deprecate median(v::AbstractArray; checknan::Bool=true) median(v)
@deprecate median(v::AbstractArray, region; checknan::Bool=true) median(v, region)
@deprecate median!(v::AbstractVector; checknan::Bool=true) median!(v)
Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ export
At_mul_Bt!,
At_rdiv_B,
At_rdiv_Bt,
call,

# scalar math
@evalpoly,
Expand Down
156 changes: 96 additions & 60 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,6 @@ const apply_type_tfunc = function (A, args...)
end
t_func[apply_type] = (1, Inf, apply_type_tfunc)

# other: apply

function tuple_tfunc(argtypes::ANY, limit)
t = argtypes
if limit
Expand Down Expand Up @@ -787,54 +785,74 @@ function to_tuple_of_Types(t::ANY)
return t
end

# do apply(af, fargs...), where af is a function value
function abstract_apply(af, aargtypes, vtypes, sv, e)
if all(x->isa(x,Tuple), aargtypes) &&
!any(isvatuple, aargtypes[1:(length(aargtypes)-1)])
e.head = :call1
# apply with known func with known tuple types
# can be collapsed to a call to the applied func
at = length(aargtypes) > 0 ?
limit_tuple_type(tuple(append_any(aargtypes...)...)) : ()
return abstract_call(af, (), at, vtypes, sv, ())
end
if is(af,tuple) && length(aargtypes)==1
# tuple(xs...)
aat = aargtypes[1]
if aat <: AbstractArray
# tuple(array...)
# TODO: > 1 array of the same type
tn = AbstractArray.name
while isa(aat, DataType)
if is(aat.name, tn)
et = aat.parameters[1]
if !isa(et,TypeVar)
return (et...)
end
end
if is(aat, Any)
break
end
aat = aat.super
end
end
return Tuple
end
if is(af,kwcall)
return Any
end
# apply known function with unknown args => f(Any...)
return abstract_call(af, (), Tuple, vtypes, sv, ())
end

function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e)
if is(f,apply) && length(fargs)>0
if isType(argtypes[1]) && isleaftype(argtypes[1].parameters[1])
af = argtypes[1].parameters[1]
if is(f,_apply) && length(fargs)>1
a2type = argtypes[2]
if isType(a2type) && isleaftype(a2type.parameters[1])
af = a2type.parameters[1]
_methods(af,(),0)
else
af = isconstantfunc(fargs[1], sv)
af = isconstantfunc(fargs[2], sv)
end

if !is(af,false)
aargtypes = map(to_tuple_of_Types, argtypes[2:end])
if all(x->isa(x,Tuple), aargtypes) &&
!any(isvatuple, aargtypes[1:(length(aargtypes)-1)])
e.head = :call1
# apply with known func with known tuple types
# can be collapsed to a call to the applied func
at = length(aargtypes) > 0 ?
limit_tuple_type(apply(tuple,aargtypes...)) : ()
return abstract_call(_ieval(af), (), at, vtypes, sv, ())
end
af = _ieval(af)
if is(af,tuple) && length(fargs)==2
# tuple(xs...)
aat = aargtypes[1]
if aat <: AbstractArray
# tuple(array...)
# TODO: > 1 array of the same type
tn = AbstractArray.name
while isa(aat, DataType)
if is(aat.name, tn)
et = aat.parameters[1]
if !isa(et,TypeVar)
return (et...)
end
end
if is(aat, Any)
break
end
aat = aat.super
end
end
return Tuple
end
if is(af,kwcall)
return Any
end
# apply known function with unknown args => f(Any...)
return abstract_call(af, (), Tuple, vtypes, sv, ())
end
if isa(af,Function) || isa(af,DataType)
aargtypes = map(to_tuple_of_Types, argtypes[3:end])
return abstract_apply(af, aargtypes, vtypes, sv, e)
end
end
# TODO: this slows down inference a lot
# if !(a2type===Function || a2type===DataType) && isleaftype(a2type)
# # would definitely use call()
# call_func = isconstantfunc(fargs[1])
# if !is(call_func,false)
# aargtypes = Any[ to_tuple_of_Types(argtypes[i]) for i=2:length(argtypes) ]
# aargtypes[1] = (aargtypes[1],) # don't splat "function"
# return abstract_apply(_ieval(call_func), tuple(aargtypes...), vtypes, sv, e)
# end
# end
return Any
end
if isgeneric(f)
return abstract_call_gf(f, fargs, argtypes, e)
Expand All @@ -849,7 +867,7 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e)
end
end
end
if !is(f,apply) && isa(e,Expr) && (isa(f,Function) || isa(f,IntrinsicFunction))
if !is(f,_apply) && isa(e,Expr) && (isa(f,Function) || isa(f,IntrinsicFunction))
e.head = :call1
end
if is(f,getfield)
Expand All @@ -859,25 +877,30 @@ function abstract_call(f, fargs, argtypes, vtypes, sv::StaticVarInfo, e)
end
end
if is(f,kwcall)
if length(argtypes) < 3
if length(argtypes) < 4
return Bottom
end
if length(fargs) < 2
if length(fargs) < 3
return Any
end
ff = isconstantfunc(fargs[1], sv)
kwcount = fargs[2]
ff = isconstantfunc(fargs[4 + 2*kwcount], sv)
if !(ff===false)
ff = _ieval(ff)
if isgeneric(ff) && isdefined(ff.env,:kwsorter)
# use the fact that kwcall(...) calls ff.env.kwsorter
kwcount = fargs[2]
posargt = argtypes[(4+2*kwcount):end]
posargt = argtypes[(5+2*kwcount):end]
return abstract_call_gf(ff.env.kwsorter, (),
tuple(Array{Any,1}, posargt...), e)
end
end
# TODO: call() case
return Any
end
if !isa(f,Function) && !isa(f,DataType) && !isa(f,IntrinsicFunction) && _iisdefined(:call)
call_func = _ieval(:call)
return abstract_call(call_func, e.args, tuple(Any[typeof(f),argtypes...]...), vtypes, sv, e)
end
rt = builtin_tfunction(f, fargs, argtypes)
#print("=> ", rt, "\n")
return rt
Expand Down Expand Up @@ -924,6 +947,10 @@ function abstract_eval_call(e, vtypes, sv::StaticVarInfo)
return st
end
end
if !(Function <: ft) && typeintersect(DataType, ft)==Bottom && _iisdefined(:call)
call_func = _ieval(:call)
return abstract_call(call_func, e.args, tuple(Any[ft,argtypes...]...), vtypes, sv, e)
end
return Any
end
#print("call ", e.args[1], argtypes, " ")
Expand Down Expand Up @@ -1313,6 +1340,8 @@ function typeinf(linfo::LambdaStaticData,atypes::Tuple,sparams::Tuple, def, cop)
end

#if dbg print("typeinf ", linfo.name, " ", atypes, "\n") end
#ccall(:jl_,Void,(Any,),linfo.name)
#ccall(:jl_,Void,(Any,),atypes)

if cop
sparams = tuple(sparams..., linfo.sparams...)
Expand Down Expand Up @@ -2650,7 +2679,14 @@ function inlining_pass(e::Expr, sv, ast)
if isType(ET)
f = ET.parameters[1]
else
f = _ieval(arg1)
f1 = f = isconstantfunc(arg1, sv)
if !is(f,false)
f = _ieval(f)
end
if f1===false || !(isa(f,Function) || isa(f,Type) || isa(f,IntrinsicFunction))
f = _ieval(:call)
e.args = Any[f, e.args...]
end
end

if is(f, ^) || is(f, .^)
Expand Down Expand Up @@ -2685,34 +2721,34 @@ function inlining_pass(e::Expr, sv, ast)
if !is(res,NF)
# iteratively inline apply(f, tuple(...), tuple(...), ...) in order
# to simplify long vararg lists as in multi-arg +
if isa(res,Expr) && is_known_call(res, apply, sv)
if isa(res,Expr) && is_known_call(res, _apply, sv)
e = res::Expr
f = apply
f = _apply
else
return (res,stmts)
end
end

if is(f,apply)
if is(f,_apply)
na = length(e.args)
newargs = cell(na-2)
for i = 3:na
newargs = cell(na-3)
for i = 4:na
aarg = e.args[i]
t = to_tuple_of_Types(exprtype(aarg))
if isa(aarg,Expr) && is_known_call(aarg, tuple, sv)
# apply(f,tuple(x,y,...)) => f(x,y,...)
newargs[i-2] = aarg.args[2:end]
newargs[i-3] = aarg.args[2:end]
elseif isa(aarg, Tuple)
newargs[i-2] = Any[ QuoteNode(x) for x in aarg ]
newargs[i-3] = Any[ QuoteNode(x) for x in aarg ]
elseif isa(t,Tuple) && !isvatuple(t) && effect_free(aarg,sv,true)
# apply(f,t::(x,y)) => f(t[1],t[2])
newargs[i-2] = Any[ mk_tupleref(aarg,j,t[j]) for j=1:length(t) ]
newargs[i-3] = Any[ mk_tupleref(aarg,j,t[j]) for j=1:length(t) ]
else
# not all args expandable
return (e,stmts)
end
end
e.args = [Any[e.args[2]], newargs...]
e.args = [Any[e.args[3]], newargs...]

# now try to inline the simplified call

Expand Down
4 changes: 2 additions & 2 deletions base/linalg/bidiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ function +(A::Bidiagonal, B::Bidiagonal)
if A.isupper==B.isupper
Bidiagonal(A.dv+B.dv, A.ev+B.ev, A.isupper)
else
apply(Tridiagonal, A.isupper ? (B.ev,A.dv+B.dv,A.ev) : (A.ev,A.dv+B.dv,B.ev))
Tridiagonal((A.isupper ? (B.ev,A.dv+B.dv,A.ev) : (A.ev,A.dv+B.dv,B.ev))...)
end
end

function -(A::Bidiagonal, B::Bidiagonal)
if A.isupper==B.isupper
Bidiagonal(A.dv-B.dv, A.ev-B.ev, A.isupper)
else
apply(Tridiagonal, A.isupper ? (-B.ev,A.dv-B.dv,A.ev) : (A.ev,A.dv-B.dv,-B.ev))
Tridiagonal((A.isupper ? (-B.ev,A.dv-B.dv,A.ev) : (A.ev,A.dv-B.dv,-B.ev))...)
end
end

Expand Down
5 changes: 3 additions & 2 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -498,12 +498,13 @@ export
getindex,
setindex!,
transpose,
ctranspose
ctranspose,
call

import Base: !, !=, $, %, .%, &, *, +, -, .!=, .+, .-, .*, ./, .<, .<=, .==, .>,
.>=, .\, .^, /, //, <, <:, <<, <=, ==, >, >=, >>, .>>, .<<, >>>,
<|, |>, \, ^, |, ~, !==, >:, colon, hcat, vcat, hvcat, getindex, setindex!,
transpose, ctranspose,
transpose, ctranspose, call,
≥, ≤, ≠, .≥, .≤, .≠, ÷, ⋅, ×, ∈, ∉, ∋, ∌, ⊆, ⊈, ⊊, ∩, ∪, √, ∛

end
2 changes: 1 addition & 1 deletion base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ eval(m,x) = Core.eval(m,x)
include = Core.include

using Core: Intrinsics, arraylen, arrayref, arrayset, arraysize,
tuplelen, tupleref, convert_default, kwcall,
tuplelen, tupleref, convert_default, kwcall, _apply,
typeassert, apply_type

include("exports.jl")
Expand Down
Loading