Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a reexported keyword for use with using, import, and importall #5626

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ jl_sym_t *compositetype_sym; jl_sym_t *type_goto_sym;
jl_sym_t *global_sym; jl_sym_t *tuple_sym;
jl_sym_t *dot_sym; jl_sym_t *newvar_sym;
jl_sym_t *boundscheck_sym; jl_sym_t *copyast_sym;
jl_sym_t *reexported_sym;

typedef struct {
int64_t a;
Expand Down
4 changes: 2 additions & 2 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ void julia_init(char *imageFile)
jl_core_module->parent = jl_main_module;
jl_set_const(jl_main_module, jl_symbol("Core"),
(jl_value_t*)jl_core_module);
jl_module_using(jl_main_module, jl_core_module);
jl_module_using(jl_main_module, jl_core_module, 0);
jl_current_module = jl_core_module;
jl_init_intrinsic_functions();
jl_init_primitives();
Expand Down Expand Up @@ -743,7 +743,7 @@ void julia_init(char *imageFile)
jl_add_standard_imports(jl_main_module);
}
// eval() uses Main by default, so Main.eval === Core.eval
jl_module_import(jl_main_module, jl_core_module, jl_symbol("eval"));
jl_module_import(jl_main_module, jl_core_module, jl_symbol("eval"), 0);
jl_current_module = jl_main_module;


Expand Down
1 change: 1 addition & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2935,4 +2935,5 @@ void jl_init_types(void)
boundscheck_sym = jl_symbol("boundscheck");
newvar_sym = jl_symbol("newvar");
copyast_sym = jl_symbol("copyast");
reexported_sym = jl_symbol("reexported");
}
3 changes: 3 additions & 0 deletions src/julia-parser.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,9 @@
(take-token s)
(loop (cons (symbol (string.sub (string nxt) 1))
path)))
((eq? nxt 'reexported)
(take-token s)
`(,word (reexported ,@(reverse path))))
(else
(error (string "invalid \"" word "\" statement")))))))

Expand Down
9 changes: 5 additions & 4 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ extern jl_sym_t *abstracttype_sym; extern jl_sym_t *bitstype_sym;
extern jl_sym_t *compositetype_sym; extern jl_sym_t *type_goto_sym;
extern jl_sym_t *global_sym; extern jl_sym_t *tuple_sym;
extern jl_sym_t *boundscheck_sym; extern jl_sym_t *copyast_sym;
extern jl_sym_t *reexported_sym;


// object accessors -----------------------------------------------------------
Expand Down Expand Up @@ -783,10 +784,10 @@ DLLEXPORT void jl_set_global(jl_module_t *m, jl_sym_t *var, jl_value_t *val);
DLLEXPORT void jl_set_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val);
DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs);
DLLEXPORT void jl_declare_constant(jl_binding_t *b);
DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from);
DLLEXPORT void jl_module_use(jl_module_t *to, jl_module_t *from, jl_sym_t *s);
DLLEXPORT void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t *s);
DLLEXPORT void jl_module_importall(jl_module_t *to, jl_module_t *from);
DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from, int reexported);
DLLEXPORT void jl_module_use(jl_module_t *to, jl_module_t *from, jl_sym_t *s, int reexported);
DLLEXPORT void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t *s, int reexported);
DLLEXPORT void jl_module_importall(jl_module_t *to, jl_module_t *from, int reexported);
DLLEXPORT void jl_module_export(jl_module_t *from, jl_sym_t *s);
void jl_add_standard_imports(jl_module_t *m);
STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name)
Expand Down
63 changes: 41 additions & 22 deletions src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jl_module_t *jl_new_module(jl_sym_t *name)
htable_new(&m->bindings, 0);
arraylist_new(&m->usings, 0);
if (jl_core_module) {
jl_module_using(m, jl_core_module);
jl_module_using(m, jl_core_module, 0);
}
// export own name, so "using Foo" makes "Foo" itself visible
jl_set_const(m, name, (jl_value_t*)m);
Expand Down Expand Up @@ -114,7 +114,7 @@ jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var)
}

static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *s,
int explici);
int explici, int reexported);

typedef struct _modstack_t {
jl_module_t *m;
Expand Down Expand Up @@ -145,7 +145,7 @@ static jl_binding_t *jl_get_binding_(jl_module_t *m, jl_sym_t *var, modstack_t *
// do a full import to prevent the result of this lookup
// from changing, for example if this var is assigned to
// later.
module_import_(m, b->owner, var, 0);
module_import_(m, b->owner, var, 0, 0);
return b;
}
}
Expand All @@ -171,7 +171,7 @@ static int eq_bindings(jl_binding_t *a, jl_binding_t *b)

// NOTE: we use explici since explicit is a C++ keyword
static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *s,
int explici)
int explici, int reexported)
{
if (to == from)
return;
Expand All @@ -187,10 +187,12 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *s,
if (bto != HT_NOTFOUND) {
if (bto == b) {
// importing a binding on top of itself. harmless.
bto->exportp |= (reexported!=0);
}
else if (bto->owner == b->owner) {
// already imported
bto->imported = (explici!=0);
bto->exportp |= (reexported!=0);
}
else if (bto->owner != to && bto->owner != NULL) {
// already imported from somewhere else
Expand Down Expand Up @@ -218,46 +220,51 @@ static void module_import_(jl_module_t *to, jl_module_t *from, jl_sym_t *s,
else {
bto->owner = b->owner;
bto->imported = (explici!=0);
bto->exportp |= (reexported!=0);
}
}
else {
jl_binding_t *nb = new_binding(s);
nb->owner = b->owner;
nb->imported = (explici!=0);
nb->exportp = (reexported!=0);
*bp = nb;
}
}
}

void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t *s)
void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t *s, int reexported)
{
module_import_(to, from, s, 1);
module_import_(to, from, s, 1, reexported);
}

void jl_module_use(jl_module_t *to, jl_module_t *from, jl_sym_t *s)
void jl_module_use(jl_module_t *to, jl_module_t *from, jl_sym_t *s, int reexported)
{
module_import_(to, from, s, 0);
module_import_(to, from, s, 0, reexported);
}

void jl_module_importall(jl_module_t *to, jl_module_t *from)
void jl_module_importall(jl_module_t *to, jl_module_t *from, int reexported)
{
void **table = from->bindings.table;
for(size_t i=1; i < from->bindings.size; i+=2) {
if (table[i] != HT_NOTFOUND) {
jl_binding_t *b = (jl_binding_t*)table[i];
if (b->exportp && (b->owner==from || b->imported))
jl_module_import(to, from, b->name);
if (b->exportp && (b->owner==from || b->imported)) {
jl_module_import(to, from, b->name, reexported);
}
}
}
}

void jl_module_using(jl_module_t *to, jl_module_t *from)
void jl_module_using(jl_module_t *to, jl_module_t *from, int reexported)
{
if (to == from)
return;
for(size_t i=0; i < to->usings.len; i++) {
if (from == to->usings.items[i])
return;
if (!reexported) {
for(size_t i=0; i < to->usings.len; i++) {
if (from == to->usings.items[i])
return;
}
}
// print a warning if something visible via this "using" conflicts with
// an existing identifier. note that an identifier added later may still
Expand All @@ -269,20 +276,32 @@ void jl_module_using(jl_module_t *to, jl_module_t *from)
if (b->exportp && (b->owner==from || b->imported)) {
jl_sym_t *var = (jl_sym_t*)table[i-1];
jl_binding_t **tobp = (jl_binding_t**)ptrhash_bp(&to->bindings, var);
if (*tobp != HT_NOTFOUND && (*tobp)->owner != NULL &&
if (*tobp != HT_NOTFOUND && (*tobp)->owner != NULL) {
// don't warn for conflicts with the module name itself.
// see issue #4715
var != to->name &&
!eq_bindings(jl_get_binding(to,var), b)) {
jl_printf(JL_STDERR,
"Warning: using %s.%s in module %s conflicts with an existing identifier.\n",
from->name->name, var->name, to->name->name);
if(var != to->name &&
!eq_bindings(jl_get_binding(to,var), b)) {
jl_printf(JL_STDERR,
"Warning: using %s.%s in module %s conflicts with an existing identifier.\n",
from->name->name, var->name, to->name->name);
}
else if (reexported) {
(*tobp)->exportp = 1;
}
}
else if (reexported) {
jl_binding_t *nb = *tobp == HT_NOTFOUND ? new_binding(var) : *tobp;
nb->owner = b->owner;
nb->imported = 0;
nb->exportp = 1;
*tobp = nb;
}
}
}
}

arraylist_push(&to->usings, from);
if (!reexported)
arraylist_push(&to->usings, from);
}

void jl_module_export(jl_module_t *from, jl_sym_t *s)
Expand Down
49 changes: 34 additions & 15 deletions src/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ jl_value_t *jl_toplevel_eval_flex(jl_value_t *e, int fast);
void jl_add_standard_imports(jl_module_t *m)
{
// using Base
jl_module_using(m, jl_base_module);
jl_module_using(m, jl_base_module, 0);
// importall Base.Operators
jl_module_importall(m, (jl_module_t*)jl_get_global(jl_base_module,
jl_symbol("Operators")));
jl_symbol("Operators")), 0);
}

extern int base_module_conflict;
Expand Down Expand Up @@ -272,9 +272,25 @@ static jl_module_t *eval_import_path_(jl_array_t *args, int retrying)
return m;
}

static jl_module_t *eval_import_path(jl_array_t *args)
static jl_module_t *eval_import_path(jl_array_t *args, jl_sym_t **name, int *reexported)
{
return eval_import_path_(args, 0);
jl_value_t *e = (jl_value_t*)jl_cellref(args,0);
if (jl_is_expr(e)) {
jl_expr_t *ex = (jl_expr_t*)e;
if (jl_array_len(args) != 1 || ex->head != reexported_sym) {
jl_errorf("invalid import statement");
return NULL;
}
*reexported = 1;
args = ex->args;
} else {
*reexported = 0;
}

jl_module_t *m = eval_import_path_(args, 0);
if (m!=NULL)
*name = (jl_sym_t*)jl_cellref(args, jl_array_len(args)-1);
return m;
}

jl_value_t *jl_toplevel_eval_body(jl_array_t *stmts);
Expand Down Expand Up @@ -309,41 +325,44 @@ jl_value_t *jl_toplevel_eval_flex(jl_value_t *e, int fast)

// handle import, using, importall, export toplevel-only forms
if (ex->head == importall_sym) {
jl_module_t *m = eval_import_path(ex->args);
int reexported;
jl_sym_t *name;
jl_module_t *m = eval_import_path(ex->args, &name, &reexported);
if (m==NULL) return jl_nothing;
jl_sym_t *name = (jl_sym_t*)jl_cellref(ex->args, jl_array_len(ex->args)-1);
if (!jl_is_symbol(name))
jl_error("syntax: malformed \"importall\" statement");
m = (jl_module_t*)jl_eval_global_var(m, name);
if (!jl_is_module(m))
jl_errorf("invalid %s statement: name exists but does not refer to a module", ex->head->name);
jl_module_importall(jl_current_module, m);
jl_errorf("invalid %s statement: name exists but does not refer to a module", ex->head->name);
jl_module_importall(jl_current_module, m, reexported);
return jl_nothing;
}

if (ex->head == using_sym) {
jl_module_t *m = eval_import_path(ex->args);
int reexported;
jl_sym_t *name;
jl_module_t *m = eval_import_path(ex->args, &name, &reexported);
if (m==NULL) return jl_nothing;
jl_sym_t *name = (jl_sym_t*)jl_cellref(ex->args, jl_array_len(ex->args)-1);
if (!jl_is_symbol(name))
jl_error("syntax: malformed \"using\" statement");
jl_module_t *u = (jl_module_t*)jl_eval_global_var(m, name);
if (jl_is_module(u)) {
jl_module_using(jl_current_module, u);
jl_module_using(jl_current_module, u, reexported);
}
else {
jl_module_use(jl_current_module, m, name);
jl_module_use(jl_current_module, m, name, reexported);
}
return jl_nothing;
}

if (ex->head == import_sym) {
jl_module_t *m = eval_import_path(ex->args);
int reexported;
jl_sym_t *name;
jl_module_t *m = eval_import_path(ex->args, &name, &reexported);
if (m==NULL) return jl_nothing;
jl_sym_t *name = (jl_sym_t*)jl_cellref(ex->args, jl_array_len(ex->args)-1);
if (!jl_is_symbol(name))
jl_error("syntax: malformed \"import\" statement");
jl_module_import(jl_current_module, m, name);
jl_module_import(jl_current_module, m, name, reexported);
return jl_nothing;
}

Expand Down
2 changes: 1 addition & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ TESTS = all core keywordargs numbers strings unicode collections hashing \
math functional bigint sorting statistics spawn parallel arpack file \
git pkg resolve suitesparse complex version pollfd mpfr broadcast \
socket floatapprox priorityqueue readdlm regex float16 combinatorics \
sysinfo rounding ranges mod2pi euler show
sysinfo rounding ranges mod2pi euler show reexported

default: all

Expand Down
43 changes: 43 additions & 0 deletions test/reexported.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module testmod
exported = true
private = true
export exported
end

module usingmod
using testmod reexported, Base.Test
@test exported == true
@test !isdefined(:private)
end

module usingtestmod
using usingmod, Base.Test
@test exported == true
@test !isdefined(:private)
end

module importmod
import testmod.private reexported
using Base.Test
@test !isdefined(:exported)
@test private == true
end

module importtestmod
using importmod, Base.Test
@test !isdefined(:exported)
@test private == true
end

module importallmod
importall testmod reexported
using Base.Test
@test exported == true
@test !isdefined(:private)
end

module importalltestmod
using importallmod, Base.Test
@test exported == true
@test !isdefined(:private)
end
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ testnames = [
"priorityqueue", "arpack", "file", "suitesparse", "version",
"resolve", "pollfd", "mpfr", "broadcast", "complex", "socket",
"floatapprox", "readdlm", "regex", "float16", "combinatorics",
"sysinfo", "rounding", "ranges", "mod2pi", "euler", "show"
"sysinfo", "rounding", "ranges", "mod2pi", "euler", "show", "reexported"
]
@unix_only push!(testnames, "unicode")

Expand Down