Skip to content

Commit

Permalink
add the ability to deprecate bindings. fixes JuliaLang#11200
Browse files Browse the repository at this point in the history
This is a rather minimal implementation that only really works for
types and functions, since it relies on printing those objects to
show the replacement. Fortunately all existing deprecated bindings
are for types.

This also avoids tab-completing deprecated names, by excluding them
from the result of `names`. The tradeoff is that it's now
impossible to enumerate deprecated names by reflection. Hopefully
that will be ok.

We could add `deprecate(:f)` calls for functions that are
entirely deprecated. Then they would be excluded from tab
completion as well.
  • Loading branch information
JeffBezanson committed Sep 15, 2015
1 parent 2c7cebd commit 1b6efc7
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 33 deletions.
56 changes: 29 additions & 27 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ function firstcaller(bt::Array{Ptr{Void},1}, funcsym::Symbol)
return C_NULL
end

deprecate(s::Symbol) = deprecate(current_module(), s)
deprecate(m::Module, s::Symbol) = ccall(:jl_deprecate_binding, Void, (Any, Any), m, s)

macro deprecate_binding(old, new)
Expr(:toplevel,
Expr(:export, esc(old)),
Expr(:(=), esc(old), esc(new)),
Expr(:call, :deprecate, Expr(:quote, old)))
end

# 0.4 deprecations

@deprecate split(x,y,l::Integer,k::Bool) split(x,y;limit=l,keep=k)
Expand All @@ -111,19 +121,17 @@ end
@deprecate rsplit(x,y,l::Integer) rsplit(x,y;limit=l)
@deprecate rsplit(x,y,k::Bool) rsplit(x,y;keep=k)

export UdpSocket
const TcpSocket = TCPSocket
const UdpSocket = UDPSocket
deprecate(:TcpSocket)
const IpAddr = IPAddr
deprecate(:IpAddr)
@deprecate_binding UdpSocket UDPSocket

@deprecate isblank(c::Char) c == ' ' || c == '\t'
@deprecate isblank(s::AbstractString) all(c -> c == ' ' || c == '\t', s)

export Nothing
const Nothing = Void

export None
const None = Union{}
@deprecate_binding Nothing Void
@deprecate_binding None Union{}

export apply
@noinline function apply(f, args...)
Expand All @@ -150,16 +158,14 @@ end
@deprecate inf{T<:AbstractFloat}(::Type{T}) convert(T,Inf)
@deprecate nan{T<:AbstractFloat}(::Type{T}) convert(T,NaN)

export String
const String = AbstractString
@deprecate_binding String AbstractString

export Uint, Uint8, Uint16, Uint32, Uint64, Uint128
const Uint = UInt
const Uint8 = UInt8
const Uint16 = UInt16
const Uint32 = UInt32
const Uint64 = UInt64
const Uint128 = UInt128
@deprecate_binding Uint UInt
@deprecate_binding Uint8 UInt8
@deprecate_binding Uint16 UInt16
@deprecate_binding Uint32 UInt32
@deprecate_binding Uint64 UInt64
@deprecate_binding Uint128 UInt128

@deprecate zero{T}(::Type{Ptr{T}}) Ptr{T}(0)
@deprecate zero{T}(x::Ptr{T}) Ptr{T}(0)
Expand All @@ -178,8 +184,7 @@ const Uint128 = UInt128
@deprecate iround(x) round(Integer,x)
@deprecate iround{T}(::Type{T},x) round(T,x)

export Base64Pipe
const Base64Pipe = Base64EncodePipe
@deprecate_binding Base64Pipe Base64EncodePipe
@deprecate base64 base64encode

@deprecate prevind(a::Any, i::Integer) i-1
Expand Down Expand Up @@ -208,8 +213,7 @@ const Base64Pipe = Base64EncodePipe
@deprecate error(ex::Exception) throw(ex)
@deprecate error{E<:Exception}(::Type{E}) throw(E())

export MemoryError
const MemoryError = OutOfMemoryError
@deprecate_binding MemoryError OutOfMemoryError

@deprecate map!(f::Callable, dest::StridedArray, A::StridedArray, B::Number) broadcast!(f, dest, A, B)
@deprecate map!(f::Callable, dest::StridedArray, A::Number, B::StridedArray) broadcast!(f, dest, A, B)
Expand Down Expand Up @@ -542,17 +546,15 @@ function start_timer(t, d, r)
error("start_timer is deprecated. Use Timer(callback, delay, repeat) instead.")
end

const UnionType = Union
export UnionType
@deprecate_binding UnionType Union

const MathConst = Irrational
@deprecate_binding MathConst Irrational

macro math_const(sym, val, def)
depwarn("@math_const is deprecated and renamed to @irrational.", symbol("@math_const"))
:(@irrational $(esc(sym)) $(esc(val)) $(esc(def)))
end

export MathConst, @math_const
export @math_const

# 11280, mmap

Expand Down Expand Up @@ -789,8 +791,7 @@ end

@deprecate iseltype(x,T) eltype(x) <: T

const FloatingPoint = AbstractFloat
export FloatingPoint
@deprecate_binding FloatingPoint AbstractFloat

# 11447

Expand All @@ -812,3 +813,4 @@ end

# 12839
const AsyncStream = IO
deprecate(:AsyncStream)
2 changes: 1 addition & 1 deletion base/docs/helpdb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6144,7 +6144,7 @@ doc"""
The distance between `x` and the next larger representable floating-point value of the same `DataType` as `x`.
"""
eps(::FloatingPoint)
eps(::AbstractFloat)

doc"""
rem1(x,m)
Expand Down
2 changes: 1 addition & 1 deletion base/require.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ end

# remote/parallel load

function source_path(default::Union(AbstractString,Nothing)="")
function source_path(default::Union(AbstractString,Void)="")
t = current_task()
while true
s = t.storage
Expand Down
24 changes: 22 additions & 2 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1399,6 +1399,21 @@ extern "C" void jl_write_malloc_log(void)

// --- constant determination ---

static void show_source_loc(JL_STREAM *out, jl_codectx_t *ctx)
{
if (ctx == NULL) return;
jl_printf(out, "in %s at %s:%d", ctx->linfo->name->name, ctx->linfo->file->name, ctx->lineno);
}

extern "C" void jl_binding_deprecation_warning(jl_binding_t *b);

static void cg_bdw(jl_binding_t *b, jl_codectx_t *ctx)
{
jl_binding_deprecation_warning(b);
show_source_loc(JL_STDERR, ctx);
jl_printf(JL_STDERR, "\n");
}

// try to statically evaluate, NULL if not possible
extern "C"
jl_value_t *jl_static_eval(jl_value_t *ex, void *ctx_, jl_module_t *mod,
Expand Down Expand Up @@ -1451,8 +1466,10 @@ jl_value_t *jl_static_eval(jl_value_t *ex, void *ctx_, jl_module_t *mod,
s = (jl_sym_t*)jl_globalref_name(ex);
if (s && jl_is_symbol(s)) {
jl_binding_t *b = jl_get_binding(jl_globalref_mod(ex), s);
if (b && b->constp)
if (b && b->constp) {
if (b->deprecated) cg_bdw(b, ctx);
return b->value;
}
}
return NULL;
}
Expand All @@ -1467,8 +1484,10 @@ jl_value_t *jl_static_eval(jl_value_t *ex, void *ctx_, jl_module_t *mod,
s = (jl_sym_t*)jl_static_eval(jl_exprarg(e,2),ctx,mod,sp,ast,sparams,allow_alloc);
if (m && jl_is_module(m) && s && jl_is_symbol(s)) {
jl_binding_t *b = jl_get_binding(m, s);
if (b && b->constp)
if (b && b->constp) {
if (b->deprecated) cg_bdw(b, ctx);
return b->value;
}
}
}
else if (fptr == &jl_f_tuple || fptr == &jl_f_instantiate_type) {
Expand Down Expand Up @@ -2983,6 +3002,7 @@ static Value *global_binding_pointer(jl_module_t *m, jl_sym_t *s,
p->addIncoming(bval, not_found);
return julia_binding_gv(builder.CreateBitCast(p, jl_ppvalue_llvmt));
}
if (b->deprecated) cg_bdw(b, ctx);
}
if (pbnd) *pbnd = b;
return julia_binding_gv(b);
Expand Down
3 changes: 2 additions & 1 deletion src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ static void jl_serialize_module(ios_t *s, jl_module_t *m)
jl_serialize_value(s, b->value);
jl_serialize_value(s, b->globalref);
jl_serialize_value(s, b->owner);
write_int8(s, (b->constp<<2) | (b->exportp<<1) | (b->imported));
write_int8(s, (b->deprecated<<3) | (b->constp<<2) | (b->exportp<<1) | (b->imported));
jl_serialize_gv(s, (jl_value_t*)b);
}
}
Expand Down Expand Up @@ -1426,6 +1426,7 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t
b->owner = (jl_module_t*)jl_deserialize_value(s, (jl_value_t**)&b->owner);
if (b->owner != NULL) jl_gc_wb(m, b->owner);
int8_t flags = read_int8(s);
b->deprecated = (flags>>3) & 1;
b->constp = (flags>>2) & 1;
b->exportp = (flags>>1) & 1;
b->imported = (flags) & 1;
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ typedef struct {
unsigned constp:1;
unsigned exportp:1;
unsigned imported:1;
unsigned deprecated:1;
} jl_binding_t;

typedef struct _jl_module_t {
Expand Down
39 changes: 38 additions & 1 deletion src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ static jl_binding_t *new_binding(jl_sym_t *name)
b->constp = 0;
b->exportp = 0;
b->imported = 0;
b->deprecated = 0;
return b;
}

Expand Down Expand Up @@ -232,11 +233,15 @@ DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var)
return jl_get_binding_(m, var, NULL);
}

void jl_binding_deprecation_warning(jl_binding_t *b);

DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var)
{
jl_binding_t *b = jl_get_binding_(m, var, NULL);
if (b == NULL)
jl_undefined_var_error(var);
if (b->deprecated)
jl_binding_deprecation_warning(b);
return b;
}

Expand Down Expand Up @@ -324,6 +329,7 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *s,
jl_binding_t *nb = new_binding(s);
nb->owner = b->owner;
nb->imported = (explici!=0);
nb->deprecated = b->deprecated;
*bp = nb;
jl_gc_wb_buf(to, nb);
}
Expand Down Expand Up @@ -431,6 +437,7 @@ jl_value_t *jl_get_global(jl_module_t *m, jl_sym_t *var)
{
jl_binding_t *b = jl_get_binding(m, var);
if (b == NULL) return NULL;
if (b->deprecated) jl_binding_deprecation_warning(b);
return b->value;
}

Expand Down Expand Up @@ -460,6 +467,35 @@ DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var)
return b && b->constp;
}

DLLEXPORT void jl_deprecate_binding(jl_module_t *m, jl_sym_t *var)
{
jl_binding_t *b = jl_get_binding(m, var);
if (b) b->deprecated = 1;
}

DLLEXPORT int jl_is_binding_deprecated(jl_module_t *m, jl_sym_t *var)
{
jl_binding_t *b = jl_get_binding(m, var);
return b && b->deprecated;
}

void jl_binding_deprecation_warning(jl_binding_t *b)
{
if (b->deprecated) {
if (b->owner)
jl_printf(JL_STDERR, "WARNING: %s.%s is deprecated", b->owner->name->name, b->name->name);
else
jl_printf(JL_STDERR, "WARNING: %s is deprecated", b->name->name);
jl_value_t *v = b->value;
if (v && (jl_is_type(v) || (jl_is_function(v) && jl_is_gf(v)))) {
jl_printf(JL_STDERR, ", use ");
jl_static_show(JL_STDERR, v);
jl_printf(JL_STDERR, " instead");
}
jl_printf(JL_STDERR, ".\n");
}
}

DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs)
{
if (b->constp && b->value != NULL) {
Expand Down Expand Up @@ -517,7 +553,8 @@ DLLEXPORT jl_value_t *jl_module_names(jl_module_t *m, int all, int imported)
for(i=1; i < m->bindings.size; i+=2) {
if (table[i] != HT_NOTFOUND) {
jl_binding_t *b = (jl_binding_t*)table[i];
if (b->exportp || ((imported || b->owner == m) && (all || m == jl_main_module))) {
if ((b->exportp || ((imported || b->owner == m) && (all || m == jl_main_module))) &&
!b->deprecated) {
jl_array_grow_end(a, 1);
//XXX: change to jl_arrayset if array storage allocation for Array{Symbols,1} changes:
jl_cellset(a, jl_array_dim0(a)-1, (jl_value_t*)b->name);
Expand Down

0 comments on commit 1b6efc7

Please sign in to comment.