Skip to content

Commit

Permalink
Tweak reassignment corner cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Keno committed Aug 10, 2024
1 parent 14bd971 commit 58ae353
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 13 deletions.
6 changes: 3 additions & 3 deletions doc/src/manual/variables-and-scoping.md
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ ERROR: invalid redefinition of constant x
julia> const y = 1.0
1.0
julia> y = 2.0
julia> const y = 2.0
WARNING: redefinition of constant y. This may fail, cause incorrect answers, or produce other errors.
2.0
```
Expand Down Expand Up @@ -782,7 +782,7 @@ julia> const a = [1]
1-element Vector{Int64}:
1
julia> a = [1]
julia> const a = [1]
WARNING: redefinition of constant a. This may fail, cause incorrect answers, or produce other errors.
1-element Vector{Int64}:
1
Expand All @@ -803,7 +803,7 @@ f (generic function with 1 method)
julia> f()
1
julia> x = 2
julia> const x = 2
WARNING: redefinition of constant x. This may fail, cause incorrect answers, or produce other errors.
2
Expand Down
22 changes: 16 additions & 6 deletions src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,13 @@ JL_DLLEXPORT jl_value_t *jl_get_binding_type(jl_module_t *m, jl_sym_t *var)
}
if (jl_bpart_is_some_guard(bpart))
return jl_nothing;
if (jl_bpart_is_some_constant(bpart))
return jl_typeof(jl_atomic_load_relaxed(&bpart->restriction));
if (jl_bpart_is_some_constant(bpart)) {
// TODO: We would like to return the type of the constant, but
// currently code relies on this returning any to bypass conversion
// before an attempted assignment to a constant.
// return jl_typeof(jl_atomic_load_relaxed(&bpart->restriction));
return (jl_value_t*)jl_any_type;
}
return jl_atomic_load_relaxed(&bpart->restriction);
}

Expand Down Expand Up @@ -652,7 +657,7 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *asname,
return;
}
jl_binding_partition_t *btopart = jl_get_binding_partition(bto, jl_current_task->world_age);
if (btopart->kind == BINDING_KIND_GUARD || btopart->kind == BINDING_KIND_IMPLICIT) {
if (btopart->kind == BINDING_KIND_GUARD || btopart->kind == BINDING_KIND_IMPLICIT || btopart->kind == BINDING_KIND_FAILED) {
btopart->kind = (explici != 0) ? BINDING_KIND_IMPORTED : BINDING_KIND_EXPLICIT;
jl_atomic_store_relaxed(&btopart->restriction, (jl_value_t*)b);
bto->deprecated |= b->deprecated; // we already warned about this above, but we might want to warn at the use sites too
Expand Down Expand Up @@ -979,10 +984,15 @@ jl_value_t *jl_check_binding_wr(jl_binding_t *b JL_PROPAGATES_ROOT, jl_module_t
jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
assert(!jl_bpart_is_some_guard(bpart) && !jl_bpart_is_some_import(bpart));
if (jl_bpart_is_some_constant(bpart)) {
if (rhs == jl_atomic_load_relaxed(&bpart->restriction))
jl_value_t *old = jl_atomic_load_relaxed(&bpart->restriction);
if (rhs == old)
return NULL;
jl_errorf("invalid redefinition of constant %s.%s",
jl_symbol_name(mod->name), jl_symbol_name(var));
if (jl_typeof(rhs) == jl_typeof(old))
jl_errorf("invalid redefinition of constant %s.%s. This redefinition may be permitted using the `const` keyword.",
jl_symbol_name(mod->name), jl_symbol_name(var));
else
jl_errorf("invalid redefinition of constant %s.%s.",
jl_symbol_name(mod->name), jl_symbol_name(var));
}
jl_value_t *old_ty = jl_atomic_load_relaxed(&bpart->restriction);
if (old_ty != (jl_value_t*)jl_any_type && jl_typeof(rhs) != old_ty) {
Expand Down
14 changes: 10 additions & 4 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -720,11 +720,17 @@ JL_DLLEXPORT jl_binding_partition_t *jl_declare_constant_val(jl_binding_t *b, jl
jl_declare_constant(b);
jl_binding_partition_t *bpart = jl_get_binding_partition(b, jl_current_task->world_age);
if (jl_atomic_load_relaxed(&bpart->restriction)) {
if (jl_egal(val, jl_atomic_load_relaxed(&bpart->restriction)))
jl_value_t *old = jl_atomic_load_relaxed(&bpart->restriction);
if (jl_egal(val, old))
return bpart;
jl_errorf("invalid redefinition of constant %s.%s",
jl_symbol_name(b->globalref->mod->name),
jl_symbol_name(b->globalref->name));
if (jl_typeof(val) != jl_typeof(old) || jl_is_type(val) || jl_is_module(val))
jl_errorf("invalid redefinition of constant %s.%s",
jl_symbol_name(b->globalref->mod->name),
jl_symbol_name(b->globalref->name));
else
jl_safe_printf("WARNING: redefinition of constant %s.%s. This may fail, cause incorrect answers, or produce other errors.\n",
jl_symbol_name(b->globalref->mod->name),
jl_symbol_name(b->globalref->name));
}
jl_atomic_store_relaxed(&bpart->restriction, val);
jl_gc_wb(bpart, val);
Expand Down
18 changes: 18 additions & 0 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3957,3 +3957,21 @@ module DeclareSetglobal
setglobal!(@__MODULE__, :DeclareMe, 1)
@test DeclareMe === 1
end

# Binding type of const (N.B.: This may change in the future)
module ConstBindingType
using Test
const x = 1
@test Core.get_binding_type(@__MODULE__, :x) === Any
end

# Explicit import may resolve using failed
module UsingFailedExplicit
using Test
module A; export x; x = 1; end
module B; export x; x = 2; end
using .A, .B
@test_throws UndefVarError x
using .A: x as x
@test x === 1
end

0 comments on commit 58ae353

Please sign in to comment.