Skip to content

Commit 3046835

Browse files
committed
Merge pull request #181 from JuliaLang/yyc/call
Implement at-compat for new style call overloading
2 parents 5b10f24 + fa91a2e commit 3046835

File tree

3 files changed

+94
-21
lines changed

3 files changed

+94
-21
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ wherever you want to use syntax that differs in the latest Julia
3636

3737
Currently, the `@compat` macro supports the following syntaxes:
3838

39+
* `@compat (a::B{T}){T}(c) = d` - the Julia 0.5-style call overload.
40+
3941
* `@compat Dict(foo => bar, baz => qux)` - type-inferred `Dict` construction. (Also works for `DataStructures.OrderedDict`)
4042

4143
* `@compat Dict{Foo,Bar}(foo => bar, baz => qux)` - type-declared `Dict` construction. (Also works for `DataStructures.OrderedDict`)

src/Compat.jl

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -375,14 +375,35 @@ if VERSION < v"0.4.0-dev+3732"
375375
end
376376
end
377377

378+
if VERSION < v"0.5.0-dev+2396"
379+
function new_style_call_overload(ex::Expr)
380+
# Not a function call
381+
((ex.head === :(=) || ex.head === :function) &&
382+
length(ex.args) == 2 && isexpr(ex.args[1], :call)) || return false
383+
callee = (ex.args[1]::Expr).args[1]
384+
# Only Expr function name can be call overload
385+
isa(callee, Expr) || return false
386+
callee = callee::Expr
387+
# (a::A)() = ...
388+
callee.head === :(::) && return true
389+
# The other case is with type parameter.
390+
# Filter out everything without one.
391+
(callee.head === :curly && length(callee.args) >= 1) || return false
392+
# Check what the type parameter applies to is a Expr(:(::))
393+
return isexpr(callee.args[1], :(::))
394+
end
395+
else
396+
new_style_call_overload(ex::Expr) = false
397+
end
398+
378399
function _compat(ex::Expr)
379-
if ex.head == :call
400+
if ex.head === :call
380401
f = ex.args[1]
381-
if VERSION < v"0.4.0-dev+980" && (f == :Dict || (isexpr(f, :curly) && length(f.args) == 3 && f.args[1] == :Dict))
402+
if VERSION < v"0.4.0-dev+980" && (f === :Dict || (isexpr(f, :curly) && length(f.args) == 3 && f.args[1] === :Dict))
382403
ex = rewrite_dict(ex)
383-
elseif VERSION < v"0.4.0-dev+980" && (f == :OrderedDict || (isexpr(f, :curly) && length(f.args) == 3 && f.args[1] == :OrderedDict))
404+
elseif VERSION < v"0.4.0-dev+980" && (f === :OrderedDict || (isexpr(f, :curly) && length(f.args) == 3 && f.args[1] === :OrderedDict))
384405
ex = rewrite_ordereddict(ex)
385-
elseif VERSION < v"0.4.0-dev+129" && (f == :split || f == :rsplit) && length(ex.args) >= 4 && isexpr(ex.args[4], :kw)
406+
elseif VERSION < v"0.4.0-dev+129" && (f === :split || f === :rsplit) && length(ex.args) >= 4 && isexpr(ex.args[4], :kw)
386407
ex = rewrite_split(ex, f)
387408
elseif VERSION < v"0.4.0-dev+3732" && haskey(calltypes, f) && length(ex.args) > 1
388409
T = ex.args[1]
@@ -391,63 +412,77 @@ function _compat(ex::Expr)
391412
else
392413
ex = Expr(:(::), Expr(:call, :convert, T, ex.args[2:end]...), T)
393414
end
394-
elseif VERSION < v"0.4.0-dev+3732" && (f == :map && haskey(calltypes, ex.args[2]) && length(ex.args) > 2)
415+
elseif VERSION < v"0.4.0-dev+3732" && (f === :map && haskey(calltypes, ex.args[2]) && length(ex.args) > 2)
395416
ex = Expr(:call, calltypes[ex.args[2]], ex.args[3:end]...)
396-
elseif VERSION < v"0.4.0-dev+1419" && isexpr(f, :curly) && f.args[1] == :Ptr && length(ex.args) == 2 && ex.args[2] == 0
417+
elseif VERSION < v"0.4.0-dev+1419" && isexpr(f, :curly) && f.args[1] === :Ptr && length(ex.args) == 2 && ex.args[2] == 0
397418
ex = Expr(:call, :zero, f)
398-
elseif VERSION < v"0.4.0-dev+4356" && f == :chol
419+
elseif VERSION < v"0.4.0-dev+4356" && f === :chol
399420
s = ex.args[3]
400-
if isexpr(s, :curly) && s.args[1] == :Val
421+
if isexpr(s, :curly) && s.args[1] === :Val
401422
ex = Expr(:call, :chol, ex.args[2], s.args[2])
402423
end
403-
elseif VERSION < v"0.4.0-dev+4739" && isexpr(f, :curly) && (f.args[1] == :Vector || f.args[1] == :Array)
404-
if f.args[1] == :Vector && length(ex.args) == 1
424+
elseif VERSION < v"0.4.0-dev+4739" && isexpr(f, :curly) && (f.args[1] === :Vector || f.args[1] === :Array)
425+
if f.args[1] === :Vector && length(ex.args) == 1
405426
ex = Expr(:call, :Array, f.args[2], 0)
406427
else
407428
ex = Expr(:call, :Array, f.args[2], ex.args[2:end]...)
408429
end
409-
elseif VERSION < v"0.4.0-dev+4389" && f == :withenv
430+
elseif VERSION < v"0.4.0-dev+4389" && f === :withenv
410431
rewrite_pairs_to_tuples!(ex)
411432
end
412-
elseif ex.head == :curly
433+
elseif ex.head === :curly
413434
f = ex.args[1]
414-
if VERSION < v"0.4.0-dev+4319" && f == :Tuple
435+
if VERSION < v"0.4.0-dev+4319" && f === :Tuple
415436
args = ex.args[2:end]
416437
has_ellipsis = any(args) do arg
417-
isa(arg, Expr) && (arg.head == :...)
438+
isa(arg, Expr) && (arg.head === :...)
418439
end
419440
ex = if has_ellipsis
420441
Expr(:call, TopNode(:tuple), args...)
421442
else
422443
Expr(:tuple, args...)
423444
end
424-
elseif VERSION < v"0.4.0-dev+5379" && f == :Union
445+
elseif VERSION < v"0.4.0-dev+5379" && f === :Union
425446
ex = Expr(:call,:Union,ex.args[2:end]...)
426447
elseif ex == :(Ptr{Void})
427448
# Do no change Ptr{Void} to Ptr{Nothing}: 0.4.0-dev+768
428449
return ex
429450
end
430-
elseif ex.head == :macrocall
451+
elseif ex.head === :macrocall
431452
f = ex.args[1]
432-
if f == symbol("@generated") && VERSION < v"0.4.0-dev+4387"
453+
if f === symbol("@generated") && VERSION < v"0.4.0-dev+4387"
433454
f = ex.args[2]
434455
if isexpr(f, :function)
435456
ex = Expr(:stagedfunction, f.args...)
436457
end
437458
end
438-
elseif VERSION < v"0.4.0-dev+5322" && ex.head == :(::) && isa(ex.args[end], Symbol)
459+
elseif VERSION < v"0.4.0-dev+5322" && ex.head === :(::) && isa(ex.args[end], Symbol)
439460
# Replace Base.Timer with Compat.Timer2 in type declarations
440-
if ex.args[end] == :Timer || ex.args[end] == :(Base.Timer)
461+
if ex.args[end] === :Timer || ex.args[end] == :(Base.Timer)
441462
ex.args[end] = :(Compat.Timer2)
442463
end
443-
elseif ex.head == :quote && isa(ex.args[1], Symbol)
464+
elseif ex.head === :quote && isa(ex.args[1], Symbol)
444465
# Passthrough
445466
return ex
467+
elseif new_style_call_overload(ex)
468+
if ((ex.args[1]::Expr).args[1]::Expr).head === :(::)
469+
# (:function, (:call, :(:(::), <1>), <2>), <body>) ->
470+
# (:function, (:call, :(Base.call), :(:(::), <1>), <2>), <body>)
471+
unshift!((ex.args[1]::Expr).args, :(Base.call))
472+
else
473+
# (:function, (:call, :(curly, :(:(::), <1>), <3>), <2>), <body>) ->
474+
# (:function, (:call, :(curly, :(Base.call), <3>), :(:(::), <1>), <2>), <body>)
475+
callexpr = ex.args[1]::Expr
476+
callee = callexpr.args[1]::Expr
477+
obj = callee.args[1]::Expr
478+
callee.args[1] = :(Base.call)
479+
insert!(callexpr.args, 2, obj)
480+
end
446481
end
447482
return Expr(ex.head, map(_compat, ex.args)...)
448483
end
449484
function _compat(ex::Symbol)
450-
if VERSION < v"0.4.0-dev+768" && ex == :Void
485+
if VERSION < v"0.4.0-dev+768" && ex === :Void
451486
return :Nothing
452487
end
453488
return ex

test/runtests.jl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,3 +857,39 @@ let
857857
foreach((args...)->push!(a,args), [2,4,6], [10,20,30])
858858
@test a == [(2,10),(4,20),(6,30)]
859859
end
860+
861+
module CallTest
862+
863+
using Base.Test, Compat
864+
865+
immutable A
866+
a
867+
end
868+
869+
immutable B{T}
870+
b::T
871+
end
872+
873+
if VERSION >= v"0.4"
874+
@compat (::Type{A})() = A(1)
875+
@compat (::Type{B})() = B{Int}()
876+
@compat (::Type{B{T}}){T}() = B{T}(zero(T))
877+
878+
@compat (a::A)() = a.a
879+
@compat (a::A)(b) = (a.a, b)
880+
@compat (b::B{T}){T}() = b.b, T
881+
@compat (b::B{T}){T}(c::T) = 1
882+
@compat (b::B{T}){T,T2}(c::T2) = 0
883+
884+
@test A() === A(1)
885+
@test B() === B(0)
886+
@test B{Float64}() === B(0.0)
887+
888+
@test A(1)() === 1
889+
@test A(1)(2) === (1, 2)
890+
@test B(0)() === (0, Int)
891+
@test B(0)(1) === 1
892+
@test B(0)(1.0) === 0
893+
end
894+
895+
end

0 commit comments

Comments
 (0)