# This file is a part of Julia. License is MIT: https://julialang.org/license # Deprecated functions and objects # # Please add new deprecations at the bottom of the file. # A function deprecated in a release will be removed in the next one. # Please also add a reference to the pull request which introduced the # deprecation. For simple cases where a direct replacement is available, # use @deprecate. @deprecate takes care of calling the replacement # and of exporting the function. # # For more complex cases, move the body of the deprecated method in this file, # and call depwarn() directly from inside it. The symbol depwarn() expects is # the name of the function, which is used to ensure that the deprecation warning # is only printed the first time for each call place. """ @deprecate old new [export_old=true] Deprecate method `old` and specify the replacement call `new`, defining a new method `old` with the specified signature in the process. To prevent `old` from being exported, set `export_old` to `false`. !!! compat "Julia 1.5" As of Julia 1.5, functions defined by `@deprecate` do not print warning when `julia` is run without the `--depwarn=yes` flag set, as the default value of `--depwarn` option is `no`. The warnings are printed from tests run by `Pkg.test()`. # Examples ```jldoctest julia> @deprecate old(x) new(x) old (generic function with 1 method) julia> @deprecate old(x) new(x) false old (generic function with 1 method) ``` Calls to `@deprecate` without explicit type-annotations will define deprecated methods accepting arguments of type `Any`. To restrict deprecation to a specific signature, annotate the arguments of `old`. For example, ```jldoctest; filter = r"in Main at.*" julia> new(x::Int) = x; julia> new(x::Float64) = 2x; julia> @deprecate old(x::Int) new(x); julia> methods(old) # 1 method for generic function "old": [1] old(x::Int64) in Main at deprecated.jl:70 ``` will define and deprecate a method `old(x::Int)` that mirrors `new(x::Int)` but will not define nor deprecate the method `old(x::Float64)`. """ macro deprecate(old, new, export_old=true) function cannot_export_nonsymbol() error( "if the third `export_old` argument is not specified or `true`, the first", " argument must be of form", " (1) `f(...)` where `f` is a symbol,", " (2) `T{...}(...)` where `T` is a symbol, or", " (3) a symbol.", ) end meta = Expr(:meta, :noinline) if isa(old, Expr) && (old.head === :call || old.head === :where) remove_linenums!(new) oldcall = sprint(show_unquoted, old) newcall = sprint(show_unquoted, new) # if old.head is a :where, step down one level to the :call to avoid code duplication below callexpr = old.head === :call ? old : old.args[1] if callexpr.head === :call fnexpr = callexpr.args[1] if fnexpr isa Expr && fnexpr.head === :curly fnexpr = fnexpr.args[1] end if export_old if fnexpr isa Symbol maybe_export = Expr(:export, esc(fnexpr)) else cannot_export_nonsymbol() end else maybe_export = nothing end else error("invalid usage of @deprecate") end Expr(:toplevel, maybe_export, :($(esc(old)) = begin $meta depwarn($"`$oldcall` is deprecated, use `$newcall` instead.", Core.Typeof($(esc(fnexpr))).name.mt.name) $(esc(new)) end)) else if export_old && !(old isa Symbol) cannot_export_nonsymbol() end Expr(:toplevel, export_old ? Expr(:export, esc(old)) : nothing, :(function $(esc(old))(args...) $meta depwarn($"`$old` is deprecated, use `$new` instead.", Core.Typeof($(esc(old))).name.mt.name) $(esc(new))(args...) end)) end end function depwarn(msg, funcsym; force::Bool=false) opts = JLOptions() if opts.depwarn == 2 throw(ErrorException(msg)) end deplevel = force || opts.depwarn == 1 ? CoreLogging.Warn : CoreLogging.BelowMinLevel @logmsg( deplevel, msg, _module=begin bt = backtrace() frame, caller = firstcaller(bt, funcsym) linfo = caller.linfo if linfo isa Core.MethodInstance def = linfo.def def isa Module ? def : def.module else Core # TODO: Is it reasonable to attribute callers without linfo to Core? end end, _file=String(caller.file), _line=caller.line, _id=(frame,funcsym), _group=:depwarn, caller=caller, maxlog=funcsym === nothing ? nothing : 1 ) nothing end firstcaller(bt::Vector, ::Nothing) = Ptr{Cvoid}(0), StackTraces.UNKNOWN firstcaller(bt::Vector, funcsym::Symbol) = firstcaller(bt, (funcsym,)) function firstcaller(bt::Vector, funcsyms) # Identify the calling line found = false for ip in bt lkups = StackTraces.lookup(ip) for lkup in lkups if lkup == StackTraces.UNKNOWN || lkup.from_c continue end if found return ip, lkup end found = lkup.func in funcsyms # look for constructor type name if !found li = lkup.linfo if li isa Core.MethodInstance ft = ccall(:jl_first_argument_datatype, Any, (Any,), (li.def::Method).sig) if isa(ft, DataType) && ft.name === Type.body.name ft = unwrap_unionall(ft.parameters[1]) found = (isa(ft, DataType) && ft.name.name in funcsyms) end end end end end return C_NULL, StackTraces.UNKNOWN end deprecate(m::Module, s::Symbol, flag=1) = ccall(:jl_deprecate_binding, Cvoid, (Any, Any, Cint), m, s, flag) macro deprecate_binding(old, new, export_old=true, dep_message=:nothing, constant=true) dep_message === :nothing && (dep_message = ", use $new instead.") return Expr(:toplevel, export_old ? Expr(:export, esc(old)) : nothing, Expr(:const, Expr(:(=), esc(Symbol(string("_dep_message_",old))), esc(dep_message))), constant ? Expr(:const, Expr(:(=), esc(old), esc(new))) : Expr(:(=), esc(old), esc(new)), Expr(:call, :deprecate, __module__, Expr(:quote, old))) end macro deprecate_stdlib(old, mod, export_old=true, newname=old) rename = old === newname ? "" : " as `$newname`" dep_message = """: it has been moved to the standard library package `$mod`$rename. Add `using $mod` to your imports.""" new = GlobalRef(Base.root_module(Base, mod), newname) return Expr(:toplevel, export_old ? Expr(:export, esc(old)) : nothing, Expr(:const, Expr(:(=), esc(Symbol(string("_dep_message_",old))), esc(dep_message))), Expr(:const, Expr(:(=), esc(old), esc(new))), Expr(:call, :deprecate, __module__, Expr(:quote, old))) end macro deprecate_moved(old, new, export_old=true) eold = esc(old) emsg = string(old, " has been moved to the package ", new, ".jl.\n", "Run `Pkg.add(\"", new, "\")` to install it, restart Julia,\n", "and then run `using ", new, "` to load it.") return Expr(:toplevel, :($eold(args...; kwargs...) = error($emsg)), export_old ? Expr(:export, eold) : nothing, Expr(:call, :deprecate, __module__, Expr(:quote, old), 2)) end # BEGIN 1.0 deprecations @deprecate one(i::CartesianIndex) oneunit(i) @deprecate one(I::Type{CartesianIndex{N}}) where {N} oneunit(I) @deprecate BigFloat(x, prec::Int) BigFloat(x; precision=prec) @deprecate BigFloat(x, prec::Int, rounding::RoundingMode) BigFloat(x, rounding; precision=prec) @deprecate BigFloat(x::Real, prec::Int) BigFloat(x; precision=prec) @deprecate BigFloat(x::Real, prec::Int, rounding::RoundingMode) BigFloat(x, rounding; precision=prec) # END 1.0 deprecations # BEGIN 1.5 deprecations """ isimmutable(v) -> Bool !!! warning Consider using `!ismutable(v)` instead, as `isimmutable(v)` will be replaced by `!ismutable(v)` in a future release. (Since Julia 1.5) Return `true` iff value `v` is immutable. See [Mutable Composite Types](@ref) for a discussion of immutability. Note that this function works on values, so if you give it a type, it will tell you that a value of `DataType` is mutable. # Examples ```jldoctest julia> isimmutable(1) true julia> isimmutable([1,2]) false ``` """ isimmutable(@nospecialize(x)) = !ismutable(x) export isimmutable # Note isimmutable is not @deprecated out of performance concerns macro get!(h, key0, default) f, l = __source__.file, __source__.line @warn "`@get!(dict, key, default)` at $f:$l is deprecated, use `get!(()->default, dict, key)` instead." return quote get!(()->$(esc(default)), $(esc(h)), $(esc(key0))) end end pointer(V::SubArray{<:Any,<:Any,<:Array,<:Tuple{Vararg{RangeIndex}}}, is::Tuple) = pointer(V, CartesianIndex(is)) # END 1.5 deprecations # BEGIN 1.6 deprecations # These changed from SimpleVector to `MethodMatch`. These definitions emulate # being a SimpleVector to ease transition for packages that make explicit # use of (internal) APIs that return raw method matches. iterate(match::Core.MethodMatch, field::Int=1) = field > nfields(match) ? nothing : (getfield(match, field), field+1) getindex(match::Core.MethodMatch, field::Int) = getfield(match, field) # these were internal functions, but some packages seem to be relying on them tuple_type_head(T::Type) = fieldtype(T, 1) tuple_type_cons(::Type, ::Type{Union{}}) = Union{} function tuple_type_cons(::Type{S}, ::Type{T}) where T<:Tuple where S @_foldable_meta Tuple{S, T.parameters...} end function parameter_upper_bound(t::UnionAll, idx) @_foldable_meta return rewrap_unionall((unwrap_unionall(t)::DataType).parameters[idx], t) end # these were internal functions, but some packages seem to be relying on them @deprecate cat_shape(dims, shape::Tuple{}, shapes::Tuple...) cat_shape(dims, shapes) false cat_shape(dims, shape::Tuple{}) = () # make sure `cat_shape(dims, ())` do not recursively calls itself @deprecate unsafe_indices(A) axes(A) false @deprecate unsafe_length(r) length(r) false # these were internal type aliases, but some pacakges seem to be relying on them const Any16{N} = Tuple{Any,Any,Any,Any,Any,Any,Any,Any, Any,Any,Any,Any,Any,Any,Any,Any,Vararg{Any,N}} const All16{T,N} = Tuple{T,T,T,T,T,T,T,T, T,T,T,T,T,T,T,T,Vararg{T,N}} # END 1.6 deprecations # BEGIN 1.7 deprecations # the plan is to eventually overload getproperty to access entries of the dict @noinline function getproperty(x::Pairs, s::Symbol) depwarn("use values(kwargs) and keys(kwargs) instead of kwargs.data and kwargs.itr", :getproperty, force=true) return getfield(x, s) end # This function was marked as experimental and not exported. @deprecate catch_stack(task=current_task(); include_bt=true) current_exceptions(task; backtrace=include_bt) false # END 1.7 deprecations # BEGIN 1.8 deprecations const var"@_inline_meta" = var"@inline" const var"@_noinline_meta" = var"@noinline" @deprecate getindex(t::Tuple, i::Real) t[convert(Int, i)] # END 1.8 deprecations # BEGIN 1.9 deprecations @deprecate splat(x) Splat(x) false # END 1.9 deprecations