diff --git a/base/Base_compiler.jl b/base/Base_compiler.jl index 781ad5c69d512..40b8ed5f81fbc 100644 --- a/base/Base_compiler.jl +++ b/base/Base_compiler.jl @@ -7,6 +7,556 @@ Core._import(Base, Core, :_eval_using, :_eval_using, true) using .Core.Intrinsics, .Core.IR +macro max_methods_1(f::Symbol) + :(typeof(function $f end).name.max_methods = 0x1) +end +macro max_methods_2(f::Symbol) + :(typeof(function $f end).name.max_methods = 0x2) +end + +# Minimize world-splitting for functions to which users or package authors +# will add more methods to. +# +# `@max_methods_2` is for functions which take type arguments and need +# a method for the bottom type. `@max_methods_1` does not suffice in that case. +# +# To re-generate the below list of functions: +# +# * Use the following script to generate the initial list. +# +# * Then, manually delete lines corresponding to functions to which +# users or package authors are not allowed to add methods to. +# +# * Then, manually adjust some lines to `@max_methods_2` where necessary. +# +# Script to generate the initial list: +# +# ```julia +# function public_generic_functions(io::IO, mod::Module) +# function f(n::Symbol) +# g = getproperty(mod, n) +# ( +# (g isa Function) && +# (!(g isa Core.IntrinsicFunction)) && # exclude intrinsic functions +# (!(g isa Core.Builtin)) && # exclude built-in functions +# Base.issingletontype(typeof(g)) && # only include functions of singleton type +# (string(n) == string(g)) && # exclude alias bindings +# (string(n)[1] != '@') && # exclude macros +# (parentmodule(g) == mod) # only include functions that belong to this module +# ) +# end +# ns = names(mod) +# it1 = Iterators.filter(f, ns) +# it2 = Iterators.map(Base.Fix1(getproperty, mod), it1) +# g1 = Base.Fix1(print, io) +# g2 = Base.Fix1(g1, "@max_methods_1 ") +# g3 = Base.Fix2(g2, '\n') +# foreach(g3, it2) +# end +# public_generic_functions(stdout, Base) +# ``` +@max_methods_1 ! +@max_methods_1 & +@max_methods_1 * +@max_methods_1 + +@max_methods_1 - +@max_methods_1 / +@max_methods_1 // +@max_methods_1 < +@max_methods_1 << +@max_methods_1 <= +@max_methods_1 == +@max_methods_1 >> +@max_methods_1 >>> +@max_methods_1 \ +@max_methods_1 ^ +@max_methods_1 abs +@max_methods_1 abs2 +@max_methods_1 accumulate +@max_methods_1 accumulate! +@max_methods_1 acos +@max_methods_1 acosh +@max_methods_1 acquire +@max_methods_1 addenv +@max_methods_1 adjoint +@max_methods_1 all +@max_methods_1 all! +@max_methods_1 allequal +@max_methods_1 allunique +@max_methods_1 angle +@max_methods_1 any +@max_methods_1 any! +@max_methods_1 append! +@max_methods_1 argmax +@max_methods_1 argmin +@max_methods_1 ascii +@max_methods_1 asin +@max_methods_1 asinh +@max_methods_1 asyncmap +@max_methods_1 asyncmap! +@max_methods_1 atan +@max_methods_1 atanh +@max_methods_1 axes +@max_methods_2 big +@max_methods_1 bind +@max_methods_1 binomial +@max_methods_1 bitreverse +@max_methods_1 bitrotate +@max_methods_1 bitstring +@max_methods_1 bswap +@max_methods_1 bytes2hex +@max_methods_1 bytesavailable +@max_methods_1 cat +@max_methods_1 cconvert +@max_methods_2 ceil +@max_methods_1 checkbounds +@max_methods_1 checked_length +@max_methods_1 checkindex +@max_methods_1 chomp +@max_methods_1 chop +@max_methods_1 chopprefix +@max_methods_1 chopsuffix +@max_methods_1 circcopy! +@max_methods_1 circshift +@max_methods_1 circshift! +@max_methods_1 cis +@max_methods_1 cispi +@max_methods_1 clamp +@max_methods_1 clamp! +@max_methods_1 cld +@max_methods_1 close +@max_methods_1 closewrite +@max_methods_1 cmp +@max_methods_1 codepoint +@max_methods_1 codeunit +@max_methods_1 codeunits +@max_methods_2 collect +@max_methods_2 complex +@max_methods_1 conj +@max_methods_1 conj! +@max_methods_1 contains +@max_methods_1 convert +@max_methods_1 copy +@max_methods_1 copy! +@max_methods_1 copyline +@max_methods_1 copysign +@max_methods_1 copyto! +@max_methods_1 copyuntil +@max_methods_1 cos +@max_methods_1 cosh +@max_methods_1 count +@max_methods_1 count! +@max_methods_1 count_ones +@max_methods_1 count_zeros +@max_methods_1 countlines +@max_methods_1 ctruncate +@max_methods_1 cumprod +@max_methods_1 cumprod! +@max_methods_1 cumsum +@max_methods_1 cumsum! +@max_methods_1 delete! +@max_methods_1 deleteat! +@max_methods_1 denominator +@max_methods_1 detach +@max_methods_1 diff +@max_methods_1 digits +@max_methods_1 digits! +@max_methods_1 displaysize +@max_methods_1 div +@max_methods_1 divrem +@max_methods_1 download +@max_methods_1 dropdims +@max_methods_1 dump +@max_methods_1 eachcol +@max_methods_1 eachindex +@max_methods_1 eachline +@max_methods_1 eachmatch +@max_methods_1 eachrow +@max_methods_1 eachrsplit +@max_methods_1 eachslice +@max_methods_1 eachsplit +@max_methods_2 elsize +@max_methods_2 eltype +@max_methods_1 empty +@max_methods_1 empty! +@max_methods_1 endswith +@max_methods_1 eof +@max_methods_2 eps +@max_methods_1 escape_microsoft_c_args +@max_methods_1 escape_raw_string +@max_methods_1 escape_string +@max_methods_1 exit +@max_methods_1 exp +@max_methods_1 exp10 +@max_methods_1 exp2 +@max_methods_1 expm1 +@max_methods_1 extrema +@max_methods_1 extrema! +@max_methods_1 factorial +@max_methods_1 fd +@max_methods_1 fdio +@max_methods_1 fetch +@max_methods_1 filesize +@max_methods_1 fill +@max_methods_1 fill! +@max_methods_1 filter +@max_methods_1 filter! +@max_methods_1 findall +@max_methods_1 findfirst +@max_methods_1 findlast +@max_methods_1 findmax +@max_methods_1 findmax! +@max_methods_1 findmin +@max_methods_1 findmin! +@max_methods_1 findnext +@max_methods_1 findprev +@max_methods_1 first +@max_methods_1 firstindex +@max_methods_1 fld +@max_methods_1 fld1 +@max_methods_1 fldmod +@max_methods_1 fldmod1 +@max_methods_1 flipsign +@max_methods_2 float +@max_methods_2 floatmax +@max_methods_2 floatmin +@max_methods_2 floor +@max_methods_1 flush +@max_methods_1 fma +@max_methods_1 foldl +@max_methods_1 foldr +@max_methods_1 foreach +@max_methods_1 front +@max_methods_1 gcd +@max_methods_1 gcdx +@max_methods_1 get +@max_methods_1 get! +@max_methods_1 getindex +@max_methods_1 getkey +@max_methods_1 getproperty +@max_methods_1 has_offset_axes +@max_methods_1 hash +@max_methods_1 haskey +@max_methods_1 hasproperty +@max_methods_1 hcat +@max_methods_1 hex2bytes +@max_methods_1 hex2bytes! +@max_methods_1 htol +@max_methods_1 hton +@max_methods_1 hvcat +@max_methods_1 hvncat +@max_methods_1 ignorestatus +@max_methods_1 imag +@max_methods_1 in +@max_methods_1 in! +@max_methods_1 indexin +@max_methods_1 insert! +@max_methods_1 insertdims +@max_methods_2 instances +@max_methods_1 intersect +@max_methods_1 intersect! +@max_methods_1 inv +@max_methods_1 invmod +@max_methods_1 invperm +@max_methods_1 invpermute! +@max_methods_1 isapprox +@max_methods_1 isascii +@max_methods_1 isassigned +@max_methods_1 isdisjoint +@max_methods_1 isdone +@max_methods_1 isempty +@max_methods_1 isequal +@max_methods_1 iseven +@max_methods_1 isexecutable +@max_methods_1 isfinite +@max_methods_1 isfull +@max_methods_1 isinf +@max_methods_1 isinteger +@max_methods_1 isless +@max_methods_1 islocked +@max_methods_1 ismalformed +@max_methods_1 ismarked +@max_methods_1 isnan +@max_methods_1 isnegative +@max_methods_1 isodd +@max_methods_1 isone +@max_methods_1 isopen +@max_methods_1 isoverlong +@max_methods_1 isperm +@max_methods_1 ispositive +@max_methods_1 ispow2 +@max_methods_1 isqrt +@max_methods_1 isreadable +@max_methods_1 isreadonly +@max_methods_1 isready +@max_methods_1 isreal +@max_methods_1 issetequal +@max_methods_1 issorted +@max_methods_1 issubnormal +@max_methods_1 issubset +@max_methods_1 isunordered +@max_methods_1 isvalid +@max_methods_1 iswritable +@max_methods_1 iszero +@max_methods_1 iterate +@max_methods_1 join +@max_methods_1 keepat! +@max_methods_1 keys +@max_methods_2 keytype +@max_methods_1 kron +@max_methods_1 kron! +@max_methods_1 last +@max_methods_1 lastindex +@max_methods_1 lcm +@max_methods_1 leading_ones +@max_methods_1 leading_zeros +@max_methods_1 length +@max_methods_1 lock +@max_methods_1 log +@max_methods_1 log10 +@max_methods_1 log1p +@max_methods_1 log2 +@max_methods_1 logrange +@max_methods_1 lpad +@max_methods_1 lstrip +@max_methods_1 ltoh +@max_methods_1 ltruncate +@max_methods_2 map +@max_methods_1 map! +@max_methods_1 mapfoldl +@max_methods_1 mapfoldr +@max_methods_1 mapreduce +@max_methods_1 mapslices +@max_methods_1 mark +@max_methods_1 match +@max_methods_1 max +@max_methods_1 maximum +@max_methods_1 maximum! +@max_methods_1 maxintfloat +@max_methods_1 merge +@max_methods_1 merge! +@max_methods_1 mergewith +@max_methods_1 mergewith! +@max_methods_1 min +@max_methods_1 minimum +@max_methods_1 minimum! +@max_methods_1 minmax +@max_methods_1 mod +@max_methods_1 mod1 +@max_methods_1 mul_hi +@max_methods_1 muladd +@max_methods_1 nand +@max_methods_1 ncodeunits +@max_methods_1 ndigits +@max_methods_1 ndims +@max_methods_1 nextfloat +@max_methods_1 nextind +@max_methods_1 nextpow +@max_methods_1 nextprod +@max_methods_1 nor +@max_methods_1 notify +@max_methods_1 ntoh +@max_methods_1 numerator +@max_methods_1 occursin +@max_methods_2 one +@max_methods_1 ones +@max_methods_2 oneunit +@max_methods_1 open +@max_methods_1 pairs +@max_methods_1 parent +@max_methods_1 parentindices +@max_methods_2 parse +@max_methods_1 peek +@max_methods_1 permute! +@max_methods_1 permutedims +@max_methods_1 permutedims! +@max_methods_1 pipeline +@max_methods_1 pointer +@max_methods_1 pop! +@max_methods_1 popat! +@max_methods_1 popfirst! +@max_methods_1 position +@max_methods_1 powermod +@max_methods_2 precision +@max_methods_1 prepend! +@max_methods_1 prevfloat +@max_methods_1 prevind +@max_methods_1 prevpow +@max_methods_1 print +@max_methods_1 println +@max_methods_1 printstyled +@max_methods_1 prod +@max_methods_1 prod! +@max_methods_1 promote_rule +@max_methods_1 promote_shape +@max_methods_1 propertynames +@max_methods_1 push! +@max_methods_1 pushfirst! +@max_methods_1 put! +@max_methods_1 rand +@max_methods_1 randn +@max_methods_1 range +@max_methods_1 rationalize +@max_methods_1 read +@max_methods_1 read! +@max_methods_1 readavailable +@max_methods_1 readbytes! +@max_methods_1 readchomp +@max_methods_1 readeach +@max_methods_1 readline +@max_methods_1 readlines +@max_methods_1 readuntil +@max_methods_2 real +@max_methods_1 reduce +@max_methods_1 reim +@max_methods_2 reinterpret +@max_methods_1 release +@max_methods_1 rem +@max_methods_1 repeat +@max_methods_1 replace +@max_methods_1 replace! +@max_methods_1 replaceproperty! +@max_methods_1 repr +@max_methods_1 require_one_based_indexing +@max_methods_1 reset +@max_methods_1 reseteof +@max_methods_1 reshape +@max_methods_1 resize! +@max_methods_1 rest +@max_methods_1 retry +@max_methods_1 reverse +@max_methods_1 reverse! +@max_methods_1 reverseind +@max_methods_1 rot180 +@max_methods_1 rotl90 +@max_methods_1 rotr90 +@max_methods_2 round +@max_methods_1 rpad +@max_methods_1 rsplit +@max_methods_1 rstrip +@max_methods_1 rtruncate +@max_methods_1 run +@max_methods_1 schedule +@max_methods_1 seek +@max_methods_1 seekend +@max_methods_1 seekstart +@max_methods_1 selectdim +@max_methods_1 setcpuaffinity +@max_methods_1 setdiff +@max_methods_1 setdiff! +@max_methods_1 setenv +@max_methods_1 setgid +@max_methods_1 setindex! +@max_methods_1 setproperty! +@max_methods_1 setpropertyonce! +@max_methods_1 setuid +@max_methods_1 shell_escape +@max_methods_1 shell_escape_csh +@max_methods_1 shell_escape_posixly +@max_methods_1 shell_escape_wincmd +@max_methods_1 shell_split +@max_methods_1 show +@max_methods_1 show_invalid +@max_methods_1 showarg +@max_methods_1 showerror +@max_methods_1 sign +@max_methods_1 signbit +@max_methods_1 signed +@max_methods_1 similar +@max_methods_1 sin +@max_methods_1 sinh +@max_methods_1 size +@max_methods_1 sizehint! +@max_methods_1 sizeof +@max_methods_1 skip +@max_methods_1 skipchars +@max_methods_1 skipmissing +@max_methods_1 sleep +@max_methods_1 sort +@max_methods_1 sort! +@max_methods_1 sortperm +@max_methods_1 sortslices +@max_methods_1 splice! +@max_methods_1 split +@max_methods_1 split_rest +@max_methods_1 sprint +@max_methods_1 sqrt +@max_methods_1 stack +@max_methods_1 startswith +@max_methods_1 stat +@max_methods_1 step +@max_methods_1 stride +@max_methods_1 strides +@max_methods_1 string +@max_methods_1 strip +@max_methods_1 success +@max_methods_1 sum +@max_methods_1 sum! +@max_methods_1 summary +@max_methods_1 swapproperty! +@max_methods_1 symdiff +@max_methods_1 symdiff! +@max_methods_1 tail +@max_methods_1 take! +@max_methods_1 takestring! +@max_methods_1 tan +@max_methods_1 tanh +@max_methods_1 thisind +@max_methods_1 timedwait +@max_methods_1 to_index +@max_methods_1 to_indices +@max_methods_1 trailing_ones +@max_methods_1 trailing_zeros +@max_methods_1 transcode +@max_methods_1 transpose +@max_methods_1 trunc +@max_methods_1 truncate +@max_methods_1 trylock +@max_methods_1 tryparse +@max_methods_1 typemax +@max_methods_1 typemin +@max_methods_1 uabs +@max_methods_1 unescape_string +@max_methods_1 union +@max_methods_1 union! +@max_methods_1 unique +@max_methods_1 unique! +@max_methods_1 unlock +@max_methods_1 unmark +@max_methods_1 unsafe_convert +@max_methods_1 unsafe_copyto! +@max_methods_1 unsafe_load +@max_methods_1 unsafe_modify! +@max_methods_1 unsafe_read +@max_methods_1 unsafe_replace! +@max_methods_1 unsafe_store! +@max_methods_1 unsafe_string +@max_methods_1 unsafe_swap! +@max_methods_1 unsafe_trunc +@max_methods_1 unsafe_wrap +@max_methods_1 unsafe_write +@max_methods_1 unsigned +@max_methods_2 valtype +@max_methods_1 values +@max_methods_1 vcat +@max_methods_1 vec +@max_methods_1 view +@max_methods_1 wait +@max_methods_1 waitall +@max_methods_1 waitany +@max_methods_1 widemul +@max_methods_2 widen +@max_methods_1 withenv +@max_methods_1 write +@max_methods_1 xor +@max_methods_1 yield +@max_methods_1 yieldto +@max_methods_2 zero +@max_methods_1 zeros +@max_methods_1 | +@max_methods_1 ~ +@max_methods_1 ⊊ + # to start, we're going to use a very simple definition of `include` # that doesn't require any function (except what we can get from the `Core` top-module) # start this big so that we don't have to resize before we have defined how to grow an array diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 0ca2c29b678dc..bad96bb81e36e 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -938,10 +938,6 @@ end ## from general iterable to any array -# This is `Experimental.@max_methods 1 function copyto! end`, which is not -# defined at this point in bootstrap. -typeof(function copyto! end).name.max_methods = UInt8(1) - function copyto!(dest::AbstractArray, src) destiter = eachindex(dest) y = iterate(destiter) diff --git a/base/error.jl b/base/error.jl index 303b516357278..c2ccd5af361c4 100644 --- a/base/error.jl +++ b/base/error.jl @@ -27,22 +27,17 @@ throw ## native julia error handling ## -# This is `Experimental.@max_methods 2 function error end`, which is not available at this point in bootstrap. # NOTE It is important to always be able to infer the return type of `error` as `Union{}`, -# but there's a hitch when a package globally sets `@max_methods 1` and it causes inference -# for `error(::Any)` to fail (JuliaLang/julia#54029). -# This definition site `@max_methods 2` setting overrides any global `@max_methods 1` settings -# on package side, guaranteeing that return type inference on `error` is successful always. +# see issue (JuliaLang/julia#54029). Ensure that method counts are small enough with +# respect to the `max_methods` value of the function. function error end -typeof(error).name.max_methods = UInt8(2) """ error(message::AbstractString) Raise an `ErrorException` with the given message. """ -error(s::AbstractString) = throw(ErrorException(s)) -error() = throw(ErrorException("")) +error(::AbstractString) """ error(msg...) @@ -51,7 +46,14 @@ Raise an `ErrorException` with a message constructed by `string(msg...)`. """ function error(s::Vararg{Any,N}) where {N} @noinline - throw(ErrorException(Main.Base.string(s...))) + exc = if s === () + ErrorException("") + elseif s isa Tuple{AbstractString} + ErrorException(s...) + else + ErrorException(Main.Base.string(s...)) + end + throw(exc) end """ diff --git a/base/essentials.jl b/base/essentials.jl index 66f7883097c32..3a8b946a9d9f8 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -531,8 +531,12 @@ julia> Base.tail(()) 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.")) +function tail(x::Tuple) + if x === () + throw(ArgumentError("Cannot call tail on an empty tuple.")) + end + argtail(x...) +end function unwrap_unionall(@nospecialize(a)) @_foldable_meta diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 37f3a3ef8436b..57d72bb3ea569 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -159,7 +159,7 @@ end length(t::NamedTuple) = nfields(t) iterate(t::NamedTuple, iter=1) = iter > nfields(t) ? nothing : (getfield(t, iter), iter + 1) rest(t::NamedTuple) = t -@inline rest(t::NamedTuple{names}, i::Int) where {names} = NamedTuple{rest(names,i)}(t) +@inline rest(t::NamedTuple{names}, i) where {names} = NamedTuple{rest(names,i::Int)}(t) firstindex(t::NamedTuple) = 1 lastindex(t::NamedTuple) = nfields(t) getindex(t::NamedTuple, i::Int) = getfield(t, i) diff --git a/base/operators.jl b/base/operators.jl index 23f03aaff0f99..b5c18da7871d9 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -223,13 +223,6 @@ isless(x::AbstractFloat, y::AbstractFloat) = (!isnan(x) & (isnan(y) | signless(x isless(x::Real, y::AbstractFloat) = (!isnan(x) & (isnan(y) | signless(x, y))) | (x < y) isless(x::AbstractFloat, y::Real ) = (!isnan(x) & (isnan(y) | signless(x, y))) | (x < y) -# Performance optimization to reduce branching -# This is useful for sorting tuples of integers -# TODO: remove this when the compiler can optimize the generic version better -# See #48724 and #48753 -isless(a::Tuple{BitInteger, BitInteger}, b::Tuple{BitInteger, BitInteger}) = - isless(a[1], b[1]) | (isequal(a[1], b[1]) & isless(a[2], b[2])) - """ isgreater(x, y) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 85a4dacbd323c..1d563890998fe 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -105,7 +105,7 @@ UInt8 See also [`ncodeunits`](@ref), [`checkbounds`](@ref). """ @propagate_inbounds codeunit(s::AbstractString, i::Integer) = i isa Int ? - throw(MethodError(codeunit, (s, i))) : codeunit(s, Int(i)) + throw(MethodError(codeunit, (s, i))) : codeunit(s, Int(i)::Int) """ isvalid(s::AbstractString, i::Integer)::Bool @@ -141,7 +141,7 @@ Stacktrace: ``` """ @propagate_inbounds isvalid(s::AbstractString, i::Integer) = i isa Int ? - throw(MethodError(isvalid, (s, i))) : isvalid(s, Int(i)) + throw(MethodError(isvalid, (s, i))) : isvalid(s, Int(i)::Int) """ iterate(s::AbstractString, i::Integer)::Union{Tuple{<:AbstractChar, Int}, Nothing} @@ -154,7 +154,7 @@ of the iteration protocol may assume that `i` is the start of a character in `s` See also [`getindex`](@ref), [`checkbounds`](@ref). """ @propagate_inbounds iterate(s::AbstractString, i::Integer) = i isa Int ? - throw(MethodError(iterate, (s, i))) : iterate(s, Int(i)) + throw(MethodError(iterate, (s, i))) : iterate(s, Int(i)::Int) ## basic generic definitions ## diff --git a/base/tuple.jl b/base/tuple.jl index ebc2cd1e53202..1b36393b64a70 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -206,8 +206,12 @@ julia> first, Base.rest(a, state) """ function rest end rest(t::Tuple) = t -rest(t::Tuple, i::Int) = ntuple(x -> getfield(t, x+i-1), length(t)-i+1) -rest(a::Union{Array,Memory,Core.SimpleVector}, i::Int=1) = a[i:end] +function rest(t::Tuple, i) + let i = i::Int + ntuple(x -> getfield(t, x+i-1), length(t)-i+1) + end +end +rest(a::Union{Array,Memory,Core.SimpleVector}, i=1) = a[(i::Int):end] rest(itr, state...) = Iterators.rest(itr, state...) """ @@ -264,9 +268,12 @@ end @eval split_rest(t::Tuple, n::Int, i=1) = ($(Expr(:meta, :aggressive_constprop)); _split_tuple(t, length(t)-n, Int(i))) -# Use dispatch to avoid a branch in first -first(::Tuple{}) = throw(ArgumentError("tuple must be non-empty")) -first(t::Tuple) = t[1] +function first(t::Tuple) + if t === () + throw(ArgumentError("tuple must be non-empty")) + end + t[1] +end # eltype @@ -571,46 +578,62 @@ function _eq(t1::Any32, t2::Any32) end const tuplehash_seed = UInt === UInt64 ? 0x77cfa1eef01bca90 : 0xf01bca90 -hash(::Tuple{}, h::UInt) = h ⊻ tuplehash_seed -hash(t::Tuple, h::UInt) = hash(t[1], hash(tail(t), h)) -function hash(t::Any32, h::UInt) - out = h ⊻ tuplehash_seed - for i = length(t):-1:1 - out = hash(t[i], out) +function hash(t::Tuple, h::UInt) + function f(t::Tuple, h::UInt) + if t === () + h ⊻ tuplehash_seed + else + hash(t[1], hash(tail(t), h)) + end + end + function f(t::Any32, h::UInt) + out = h ⊻ tuplehash_seed + for i = length(t):-1:1 + out = hash(t[i], out) + end + return out end - return out + f(t, h) end -<(::Tuple{}, ::Tuple{}) = false -<(::Tuple{}, ::Tuple) = true -<(::Tuple, ::Tuple{}) = false function <(t1::Tuple, t2::Tuple) - a, b = t1[1], t2[1] - eq = (a == b) - if ismissing(eq) - return missing - elseif !eq - return a < b - end - return tail(t1) < tail(t2) -end -function <(t1::Any32, t2::Any32) - n1, n2 = length(t1), length(t2) - for i = 1:min(n1, n2) - a, b = t1[i], t2[i] + function f(t1::Tuple, t2::Tuple) + if t2 === () + return false + end + if t1 === () + return true + end + a, b = t1[1], t2[1] eq = (a == b) if ismissing(eq) return missing elseif !eq - return a < b + return a < b end + return tail(t1) < tail(t2) end - return n1 < n2 + function f(t1::Any32, t2::Any32) + n1, n2 = length(t1), length(t2) + for i = 1:min(n1, n2) + a, b = t1[i], t2[i] + eq = (a == b) + if ismissing(eq) + return missing + elseif !eq + return a < b + end + end + return n1 < n2 + end + f(t1, t2) end -isless(::Tuple{}, ::Tuple{}) = false -isless(::Tuple{}, ::Tuple) = true -isless(::Tuple, ::Tuple{}) = false +# copy of `BitInteger` defined later during bootstrap in int.jl +const _BitInteger = Union{ + Int8, Int16, Int32, Int64, Int128, + UInt8, UInt16, UInt32, UInt64, UInt128, +} """ isless(t1::Tuple, t2::Tuple) @@ -618,24 +641,41 @@ isless(::Tuple, ::Tuple{}) = false Return `true` when `t1` is less than `t2` in lexicographic order. """ function isless(t1::Tuple, t2::Tuple) - a, b = t1[1], t2[1] - isless(a, b) || (isequal(a, b) && isless(tail(t1), tail(t2))) -end -function isless(t1::Any32, t2::Any32) - n1, n2 = length(t1), length(t2) - for i = 1:min(n1, n2) - a, b = t1[i], t2[i] - if !isequal(a, b) - return isless(a, b) + function f(t1::Tuple, t2::Tuple) + if t2 === () + return false + end + if t1 === () + return true + end + a, b = t1[1], t2[1] + isless(a, b) || (isequal(a, b) && isless(tail(t1), tail(t2))) + end + function f(t1::Any32, t2::Any32) + n1, n2 = length(t1), length(t2) + for i = 1:min(n1, n2) + a, b = t1[i], t2[i] + if !isequal(a, b) + return isless(a, b) + end end + return n1 < n2 end - return n1 < n2 + # Performance optimization to reduce branching + # This is useful for sorting tuples of integers + # TODO: remove this when the compiler can optimize the generic version better + # See #48724 and #48753 + function f(a::Tuple{_BitInteger, _BitInteger}, b::Tuple{_BitInteger, _BitInteger}) + isless(a[1], b[1]) | (isequal(a[1], b[1]) & isless(a[2], b[2])) + end + f(t1, t2) end ## functions ## -isempty(x::Tuple{}) = true -isempty(@nospecialize x::Tuple) = false +function isempty(x::Tuple) + x === () +end revargs() = () revargs(x, r...) = (revargs(r...)..., x) @@ -673,11 +713,19 @@ empty(@nospecialize x::Tuple) = () foreach(f, itr::Tuple) = foldl((_, x) -> (f(x); nothing), itr, init=nothing) foreach(f, itr::Tuple, itrs::Tuple...) = foldl((_, xs) -> (f(xs...); nothing), zip(itr, itrs...), init=nothing) -circshift((@nospecialize t::Union{Tuple{},Tuple{Any}}), @nospecialize _::Integer) = t -circshift(t::Tuple{Any,Any}, shift::Integer) = iseven(shift) ? t : reverse(t) -function circshift(x::Tuple{Any,Any,Any,Vararg{Any,N}}, shift::Integer) where {N} +function circshift(x::Tuple, shift::Integer) @inline - len = N + 3 + if (x === ()) || (x isa Tuple{Any}) + return x + end + if x isa Tuple{Any,Any} + return if iseven(shift) + x + else + reverse(x) + end + end + len = length(x) j = mod1(shift, len) ntuple(k -> getindex(x, k-j+ifelse(k>j,0,len)), Val(len))::Tuple end diff --git a/test/core.jl b/test/core.jl index 84444ecb725d7..004a352f5f75f 100644 --- a/test/core.jl +++ b/test/core.jl @@ -8193,6 +8193,25 @@ foo46503(a::Int, b::Nothing) = @invoke foo46503(a::Any, b) foo46503(@nospecialize(a), b::Union{Nothing, Float64}) = rand() + 10 @test 10 <= foo46503(1, nothing) <= 11 +@testset "inference for `rest` with unknown state argument types" begin + @testset "`Array`, `Memory`" begin + for typ in (Vector{Float32}, Matrix{Float32}, Memory{Float32}) + @test (isconcretetype ∘ Base.infer_return_type)(Base.rest, Tuple{typ, Any}) + for e in (Base.Compiler.is_terminates, Base.Compiler.is_notaskstate, Base.Compiler.is_nonoverlayed) + @test (e ∘ Base.infer_effects)(Base.rest, Tuple{typ, Any}) + end + end + end + @testset "`Tuple`" begin + typ = NTuple{5, Float32} + @test Base.infer_return_type(Base.rest, Tuple{typ, Any}) <: Tuple + end + @testset "`NamedTuple`" begin + typ = NamedTuple{(:a, :b, :c, :d, :e), NTuple{5, Float32}} + @test Base.infer_return_type(Base.rest, Tuple{typ, Any}) <: NamedTuple + end +end + @testset "effect override on Symbol(::String)" begin @test Core.Compiler.is_foldable(Base.infer_effects(Symbol, (String,))) end diff --git a/test/faulty_constructor_method_should_not_cause_stack_overflows.jl b/test/faulty_constructor_method_should_not_cause_stack_overflows.jl index 8dede73e2ae7a..08c9c1d1e3b09 100644 --- a/test/faulty_constructor_method_should_not_cause_stack_overflows.jl +++ b/test/faulty_constructor_method_should_not_cause_stack_overflows.jl @@ -1,3 +1,4 @@ +# new types with invalid constructors for (typ, sup) in ( (:Char, :AbstractChar), (:String, :AbstractString), @@ -9,6 +10,18 @@ for (typ, sup) in ( @eval function Base.$typ(x::$fau) x end end +# valid new subtype of `AbstractString` +struct MyString <: AbstractString + str::String +end +Base.lastindex(s::MyString) = lastindex(s.str) +Base.iterate(s::MyString) = iterate(s, 1) +Base.iterate(s::MyString, state) = iterate(s, Int(state)::Int) +Base.iterate(s::MyString, state::Integer) = iterate(s, Int(state)::Int) +Base.iterate(s::MyString, state::Int) = iterate(s.str, state) +Base.isequal(a::MyString, b::MyString) = isequal(a.str, b.str) +Base.:(==)(a::MyString, b::MyString) = (a.str == b.str) + using Test using Unicode: Unicode @@ -39,14 +52,18 @@ using Unicode: Unicode end @testset let x = FaultyInt() @test_throws exc readbytes!(IOBuffer(), Vector{UInt8}(undef, 0), x) - @test_throws exc length("", x, x) - @test_throws exc thisind("", x) - @test_throws exc prevind("", x) - @test_throws exc prevind("", x, x) - @test_throws exc nextind("", x) - @test_throws exc nextind("", x, x) - @test_throws exc codeunit("", x) - @test_throws exc SubString("", x, x) + for s in ("", MyString("")) + @test_throws exc iterate(s, x) + @test_throws exc isvalid(s, x) + @test_throws exc length(s, x, x) + @test_throws exc thisind(s, x) + @test_throws exc prevind(s, x) + @test_throws exc prevind(s, x, x) + @test_throws exc nextind(s, x) + @test_throws exc nextind(s, x, x) + @test_throws exc codeunit(s, x) + @test_throws exc SubString(s, x, x) + end end @testset let x = FaultyUInt32() @test_throws exc Char(x) diff --git a/test/rational.jl b/test/rational.jl index 93b049f22f465..d5b405b7e7fed 100644 --- a/test/rational.jl +++ b/test/rational.jl @@ -838,7 +838,7 @@ end @test Core.Compiler.return_type(-, NTuple{2, Rational}) == Rational A=Rational[1 1 1; 2 2 2; 3 3 3] - @test @inferred(A*A) isa Matrix{Rational} + @test @inferred(A*A) isa Matrix end @testset "issue #42560" begin diff --git a/test/tuple.jl b/test/tuple.jl index 1f5714415e21c..2e71e26286f05 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -855,6 +855,18 @@ end @test Val{Tuple{Int64, Vararg{Int32,N}} where N} === Val{Tuple{Int64, Vararg{Int32}}} @test Val{Tuple{Int32, Vararg{Int64}}} === Val{Tuple{Int32, Vararg{Int64,N}} where N} +@testset "avoid method proliferation" begin + t = isone ∘ length ∘ methods + @test t(circshift, Tuple{Tuple, Integer}) + @test t(hash, Tuple{Tuple, UInt}) + for f in (Base.tail, first, isempty) + @test t(f, Tuple{Tuple}) + end + for f in (<, isless, ==, isequal) + @test t(f, Tuple{Tuple, Tuple}) + end +end + @testset "from Pair, issue #52636" begin pair = (1 => "2") @test (1, "2") == @inferred Tuple(pair)