Skip to content

reduce usage of _pure_meta #32427

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
Jul 22, 2020
Merged
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: 1 addition & 5 deletions base/bool.jl
Original file line number Diff line number Diff line change
@@ -30,11 +30,7 @@ julia> .![true false true]
0 1 0
```
"""
function !(x::Bool)
## We need a better heuristic to detect this automatically
@_pure_meta
return not_int(x)
end
!(x::Bool) = not_int(x)

(~)(x::Bool) = !x
(&)(x::Bool, y::Bool) = and_int(x, y)
7 changes: 7 additions & 0 deletions base/compiler/compiler.jl
Original file line number Diff line number Diff line change
@@ -78,6 +78,13 @@ using .Iterators: zip, enumerate
using .Iterators: Flatten, Filter, product # for generators
include("namedtuple.jl")

ntuple(f, ::Val{0}) = ()
ntuple(f, ::Val{1}) = (@_inline_meta; (f(1),))
ntuple(f, ::Val{2}) = (@_inline_meta; (f(1), f(2)))
ntuple(f, ::Val{3}) = (@_inline_meta; (f(1), f(2), f(3)))
ntuple(f, ::Val{n}) where {n} = ntuple(f, n::Int)
ntuple(f, n) = (Any[f(i) for i = 1:n]...,)

# core docsystem
include("docs/core.jl")

14 changes: 9 additions & 5 deletions base/compiler/tfuncs.jl
Original file line number Diff line number Diff line change
@@ -894,12 +894,16 @@ function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const)
isa(fld, Int) || return false
ftypes = datatype_fieldtypes(u)
nf = length(ftypes)
if u.name === Tuple.name && fld >= nf && isvarargtype(ftypes[nf])
# If we don't know the exact type, the length of the tuple will be determined
# at runtime and we can't say anything.
return exact
fld >= 1 || return false
if u.name === Tuple.name && nf > 0 && isvarargtype(ftypes[nf])
if !exact && fld >= nf
# If we don't know the exact type, the length of the tuple will be determined
# at runtime and we can't say anything.
return false
end
elseif fld > nf
return false
end
(fld >= 1 && fld <= nf) || return false
return true
end

150 changes: 78 additions & 72 deletions base/essentials.jl
Original file line number Diff line number Diff line change
@@ -106,6 +106,40 @@ macro specialize(vars...)
return Expr(:meta, :specialize, vars...)
end

"""
@isdefined s -> Bool

Tests whether variable `s` is defined in the current scope.

See also [`isdefined`](@ref).

# Examples
```jldoctest
julia> @isdefined newvar
false

julia> newvar = 1
1

julia> @isdefined newvar
true

julia> function f()
println(@isdefined x)
x = 3
println(@isdefined x)
end
f (generic function with 1 method)

julia> f()
false
true
```
"""
macro isdefined(s::Symbol)
return Expr(:escape, Expr(:isdefined, s))
end

macro _pure_meta()
return Expr(:meta, :pure)
end
@@ -207,31 +241,6 @@ ERROR: ArgumentError: Cannot call tail on an empty tuple.
tail(x::Tuple) = argtail(x...)
tail(::Tuple{}) = throw(ArgumentError("Cannot call tail on an empty tuple."))

tuple_type_head(T::Type) = (@_pure_meta; fieldtype(T, 1))

function tuple_type_tail(T::Type)
@_pure_meta
if isa(T, UnionAll)
return UnionAll(T.var, tuple_type_tail(T.body))
elseif isa(T, Union)
return Union{tuple_type_tail(T.a), tuple_type_tail(T.b)}
else
T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,)))
if isvatuple(T) && length(T.parameters) == 1
va = T.parameters[1]
(isa(va, DataType) && isa(va.parameters[2], Int)) || return T
return Tuple{Vararg{va.parameters[1], va.parameters[2]-1}}
end
return Tuple{argtail(T.parameters...)...}
end
end

tuple_type_cons(::Type, ::Type{Union{}}) = Union{}
function tuple_type_cons(::Type{S}, ::Type{T}) where T<:Tuple where S
Copy link
Member

Choose a reason for hiding this comment

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

Some important packages seem to use this; we should add it back in base/deprecated.jl.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, tuple_type_head as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

But not tuple_type_tail?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, right, that one was still in use by _totuple

@_pure_meta
Tuple{S, T.parameters...}
end

function unwrap_unionall(@nospecialize(a))
while isa(a,UnionAll)
a = a.body
@@ -248,7 +257,7 @@ end

# replace TypeVars in all enclosing UnionAlls with fresh TypeVars
function rename_unionall(@nospecialize(u))
if !isa(u,UnionAll)
if !isa(u, UnionAll)
return u
end
body = rename_unionall(u.body)
@@ -301,52 +310,49 @@ function typename(a::Union)
end
typename(union::UnionAll) = typename(union.body)

const AtLeast1 = Tuple{Any, Vararg{Any}}

# converting to empty tuple type
convert(::Type{Tuple{}}, ::Tuple{}) = ()
convert(::Type{Tuple{}}, x::AtLeast1) = throw(MethodError(convert, (Tuple{}, x)))

# converting to tuple types with at least one element
convert(::Type{T}, x::T) where {T<:AtLeast1} = x
convert(::Type{T}, x::AtLeast1) where {T<:AtLeast1} =
(convert(tuple_type_head(T), x[1]), convert(tuple_type_tail(T), tail(x))...)

# converting to Vararg tuple types
convert(::Type{Tuple{Vararg{V}}}, x::Tuple{Vararg{V}}) where {V} = x
convert(T::Type{Tuple{Vararg{V}}}, x::Tuple) where {V} =
(convert(tuple_type_head(T), x[1]), convert(T, tail(x))...)

# TODO: the following definitions are equivalent (behaviorally) to the above method
# I think they may be faster / more efficient for inference,
# if we could enable them, but are they?
# TODO: These currently can't be used (#21026, #23017) since with
# z(::Type{<:Tuple{Vararg{T}}}) where {T} = T
# calling
# z(Tuple{Val{T}} where T)
# fails, even though `Type{Tuple{Val}} == Type{Tuple{Val{S}} where S}`
# and so T should be `Val` (aka `Val{S} where S`)
#convert(_::Type{Tuple{S}}, x::Tuple{S}) where {S} = x
#convert(_::Type{Tuple{S}}, x::Tuple{Any}) where {S} = (convert(S, x[1]),)
#convert(_::Type{T}, x::T) where {S, N, T<:Tuple{S, Vararg{S, N}}} = x
#convert(_::Type{Tuple{S, Vararg{S, N}}},
# x::Tuple{Any, Vararg{Any, N}}) where
# {S, N} = cnvt_all(S, x...)
#convert(_::Type{Tuple{Vararg{S, N}}},
# x::Tuple{Vararg{Any, N}}) where
# {S, N} = cnvt_all(S, x...)
# TODO: These are similar to the methods we currently use but cnvt_all might work better:
#convert(_::Type{Tuple{Vararg{S}}},
# x::Tuple{Any, Vararg{Any}}) where
# {S} = cnvt_all(S, x...)
#convert(_::Type{Tuple{Vararg{S}}},
# x::Tuple{Vararg{Any}}) where
# {S} = cnvt_all(S, x...)
#cnvt_all(T) = ()
#cnvt_all(T, x, rest...) = (convert(T, x), cnvt_all(T, rest...)...)
# TODO: These may be necessary if the above are enabled
_tuple_error(T::Type, x) = (@_noinline_meta; throw(MethodError(convert, (T, x))))

convert(::Type{T}, x::T) where {T<:Tuple} = x
function convert(::Type{T}, x::NTuple{N,Any}) where {N, T<:Tuple}
# First see if there could be any conversion of the input type that'd be a subtype of the output.
# If not, we'll throw an explicit MethodError (otherwise, it might throw a typeassert).
if typeintersect(NTuple{N,Any}, T) === Union{}
_tuple_error(T, x)
end
cvt1(n) = (@_inline_meta; convert(fieldtype(T, n), getfield(x, n, #=boundscheck=#false)))
return ntuple(cvt1, Val(N))::NTuple{N,Any}
end

# optimizations?
# converting to tuple types of fixed length
#convert(::Type{T}, x::T) where {N, T<:NTuple{N,Any}} = x
#convert(::Type{T}, x::NTuple{N,Any}) where {N, T<:NTuple{N,Any}} =
# ntuple(n -> convert(fieldtype(T, n), x[n]), Val(N))
#convert(::Type{T}, x::Tuple{Vararg{Any}}) where {N, T<:NTuple{N,Any}} =
# throw(MethodError(convert, (T, x)))
# converting to tuple types of indefinite length
#convert(::Type{Tuple{Vararg{V}}}, x::Tuple{Vararg{V}}) where {V} = x
#convert(::Type{NTuple{N, V}}, x::NTuple{N, V}) where {N, V} = x
#function convert(T::Type{Tuple{Vararg{V}}}, x::Tuple) where {V}
# @isdefined(V) || (V = fieldtype(T, 1))
# return map(t -> convert(V, t), x)
#end
#function convert(T::Type{NTuple{N, V}}, x::NTuple{N, Any}) where {N, V}
# @isdefined(V) || (V = fieldtype(T, 1))
# return map(t -> convert(V, t), x)
#end
# short tuples
#convert(::Type{Tuple{}}, ::Tuple{}) = ()
#convert(::Type{Tuple{Vararg{S}}} where S, ::Tuple{}) = ()
#convert(::Type{Tuple{S}}, x::Tuple{S}) where {S} = x
#convert(::Type{Tuple{S, T}}, x::Tuple{S, T}) where {S, T} = x
#convert(::Type{Tuple{S, T, U}}, x::Tuple{S, T, U}) where {S, T, U} = x
#convert(::Type{Tuple{S}}, x::Tuple{Any}) where {S} = (convert(S, x[1]),)
#convert(::Type{Tuple{S, T}}, x::Tuple{Any, Any}) where {S, T} = (convert(S, x[1]), convert(T, x[2]),)
#convert(::Type{Tuple{S, T, U}}, x::Tuple{Any, Any, Any}) where {S, T, U} = (convert(S, x[1]), convert(T, x[2]), convert(U, x[3]))
#convert(::Type{Tuple{}}, x::Tuple) = _tuple_error(Tuple{}, x)
#convert(::Type{Tuple{S}}, x::Tuple) = _tuple_error(Tuple{S}, x)
#convert(::Type{Tuple{S, T}}, x::Tuple{Any, Any}) where {S, T} =_tuple_error(Tuple{S, T}, x)
#convert(::Type{Tuple{S, T, U}}, x::Tuple{Any, Any, Any}) where {S, T, U} = _tuple_error(Tuple{S, T, U}, x)

"""
oftype(x, y)
@@ -695,7 +701,7 @@ julia> f(Val(true))
struct Val{x}
end

Val(x) = (@_pure_meta; Val{x}())
Val(x) = Val{x}()

"""
invokelatest(f, args...; kwargs...)
Loading