# 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: # the first argument is the signature of the deprecated method, the second one # is the call which replaces it. Remove the definition of the deprecated method # and unexport it, as @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. macro deprecate(old, new, ex=true) meta = Expr(:meta, :noinline) if isa(old, Symbol) oldname = Expr(:quote, old) newname = Expr(:quote, new) Expr(:toplevel, ex ? 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)) elseif 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 if isa(callexpr.args[1], Symbol) oldsym = callexpr.args[1]::Symbol elseif isa(callexpr.args[1], Expr) && callexpr.args[1].head == :curly oldsym = callexpr.args[1].args[1]::Symbol else error("invalid usage of @deprecate") end else error("invalid usage of @deprecate") end Expr(:toplevel, ex ? Expr(:export, esc(oldsym)) : nothing, :($(esc(old)) = begin $meta depwarn($"`$oldcall` is deprecated, use `$newcall` instead.", Core.Typeof($(esc(oldsym))).name.mt.name) $(esc(new)) end)) else error("invalid usage of @deprecate") end end function depwarn(msg, funcsym) opts = JLOptions() if opts.depwarn == 2 throw(ErrorException(msg)) end deplevel = opts.depwarn == 1 ? CoreLogging.Warn : CoreLogging.BelowMinLevel @logmsg( deplevel, msg, _module=begin bt = backtrace() frame, caller = firstcaller(bt, funcsym) # TODO: Is it reasonable to attribute callers without linfo to Core? caller.linfo isa Core.MethodInstance ? caller.linfo.def.module : Core 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 lkup = StackTraces.UNKNOWN found_frame = Ptr{Cvoid}(0) for frame in bt lkups = StackTraces.lookup(frame) for outer lkup in lkups if lkup == StackTraces.UNKNOWN || lkup.from_c continue end if found found_frame = frame @goto found end found = lkup.func in funcsyms # look for constructor type name if !found && lkup.linfo isa Core.MethodInstance li = lkup.linfo ft = ccall(:jl_first_argument_datatype, Any, (Any,), li.def.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 return found_frame, StackTraces.UNKNOWN @label found return found_frame, lkup 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 0.7 deprecations function promote_eltype_op end # END 0.7 deprecations # BEGIN 1.0 deprecations # END 1.0 deprecations