Skip to content

Commit 25e3712

Browse files
authored
Merge pull request #15850 from JuliaLang/yyc/macro-curmodule
Fix macro hygiene when calling the macro in the same module.
2 parents a304c55 + 173cc40 commit 25e3712

10 files changed

+126
-31
lines changed

base/docs/Docs.jl

+3
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,9 @@ function docm(meta, ex, define = true)
606606
# Don't try to redefine expressions. This is only needed for `Base` img gen since
607607
# otherwise calling `loaddocs` would redefine all documented functions and types.
608608
def = define ? x : nothing
609+
if isa(x, GlobalRef) && (x::GlobalRef).mod == current_module()
610+
x = (x::GlobalRef).name
611+
end
609612

610613
# Keywords using the `@kw_str` macro in `base/docs/basedocs.jl`.
611614
#

base/linalg/factorization.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ transpose(F::Factorization) = error("transpose not implemented for $(typeof(F))"
99
ctranspose(F::Factorization) = error("ctranspose not implemented for $(typeof(F))")
1010

1111
macro assertposdef(A, info)
12-
:(($info)==0 ? $A : throw(PosDefException($info)))
12+
:($(esc(info)) == 0 ? $(esc(A)) : throw(PosDefException($(esc(info)))))
1313
end
1414

1515
macro assertnonsingular(A, info)
16-
:(($info)==0 ? $A : throw(SingularException($info)))
16+
:($(esc(info)) == 0 ? $(esc(A)) : throw(SingularException($(esc(info)))))
1717
end
1818

1919
function logdet(F::Factorization)

base/sparse/cholmod_h.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,5 @@ type CHOLMODException <: Exception
7575
end
7676

7777
macro isok(A)
78-
:($A == TRUE || throw(CHOLMODException("")))
78+
:($(esc(A)) == TRUE || throw(CHOLMODException("")))
7979
end

base/sparse/umfpack.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function umferror(status::Integer)
5454
end
5555

5656
macro isok(A)
57-
:(umferror($A))
57+
:(umferror($(esc(A))))
5858
end
5959

6060
# check the size of SuiteSparse_long

src/ast.c

+32-14
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,18 @@ value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint32_t na
108108
jl_ptls_t ptls = jl_get_ptls_states();
109109
// tells whether a var is defined in and *by* the current module
110110
argcount(fl_ctx, "defined-julia-global", nargs, 1);
111-
(void)tosymbol(fl_ctx, args[0], "defined-julia-global");
112-
if (ptls->current_module == NULL)
111+
jl_module_t *mod = ptls->current_module;
112+
jl_sym_t *sym = (jl_sym_t*)scm_to_julia(fl_ctx, args[0], 0);
113+
if (jl_is_globalref(sym)) {
114+
mod = jl_globalref_mod(sym);
115+
sym = jl_globalref_name(sym);
116+
}
117+
if (!jl_is_symbol(sym))
118+
type_error(fl_ctx, "defined-julia-global", "symbol", args[0]);
119+
if (!mod)
113120
return fl_ctx->F;
114-
jl_sym_t *var = jl_symbol(symbol_name(fl_ctx, args[0]));
115-
jl_binding_t *b =
116-
(jl_binding_t*)ptrhash_get(&ptls->current_module->bindings, var);
117-
return (b != HT_NOTFOUND && b->owner==ptls->current_module) ? fl_ctx->T : fl_ctx->F;
121+
jl_binding_t *b = (jl_binding_t*)ptrhash_get(&mod->bindings, sym);
122+
return (b != HT_NOTFOUND && b->owner == mod) ? fl_ctx->T : fl_ctx->F;
118123
}
119124

120125
value_t fl_current_julia_module(fl_context_t *fl_ctx, value_t *args, uint32_t nargs)
@@ -177,14 +182,14 @@ value_t fl_invoke_julia_macro(fl_context_t *fl_ctx, value_t *args, uint32_t narg
177182
fl_gc_handle(fl_ctx, &scm);
178183
value_t scmresult;
179184
jl_module_t *defmod = mfunc->def->module;
180-
if (defmod == NULL || defmod == ptls->current_module) {
181-
scmresult = fl_cons(fl_ctx, scm, fl_ctx->F);
182-
}
183-
else {
184-
value_t opaque = cvalue(fl_ctx, jl_ast_ctx(fl_ctx)->jvtype, sizeof(void*));
185-
*(jl_value_t**)cv_data((cvalue_t*)ptr(opaque)) = (jl_value_t*)defmod;
186-
scmresult = fl_cons(fl_ctx, scm, opaque);
187-
}
185+
/* if (defmod == NULL || defmod == ptls->current_module) { */
186+
/* scmresult = fl_cons(fl_ctx, scm, fl_ctx->F); */
187+
/* } */
188+
/* else { */
189+
value_t opaque = cvalue(fl_ctx, jl_ast_ctx(fl_ctx)->jvtype, sizeof(void*));
190+
*(jl_value_t**)cv_data((cvalue_t*)ptr(opaque)) = (jl_value_t*)defmod;
191+
scmresult = fl_cons(fl_ctx, scm, opaque);
192+
/* } */
188193
fl_free_gc_handles(fl_ctx, 1);
189194

190195
JL_GC_POP();
@@ -610,6 +615,19 @@ static value_t julia_to_scm_(fl_context_t *fl_ctx, jl_value_t *v)
610615
return julia_to_list2(fl_ctx, (jl_value_t*)inert_sym, jl_fieldref(v,0));
611616
if (jl_typeis(v, jl_newvarnode_type))
612617
return julia_to_list2(fl_ctx, (jl_value_t*)newvar_sym, jl_fieldref(v,0));
618+
if (jl_typeis(v, jl_globalref_type)) {
619+
jl_module_t *m = jl_globalref_mod(v);
620+
jl_sym_t *sym = jl_globalref_name(v);
621+
if (m == jl_core_module)
622+
return julia_to_list2(fl_ctx, (jl_value_t*)core_sym,
623+
(jl_value_t*)sym);
624+
value_t args = julia_to_list2(fl_ctx, (jl_value_t*)m, (jl_value_t*)sym);
625+
fl_gc_handle(fl_ctx, &args);
626+
value_t hd = julia_to_scm_(fl_ctx, (jl_value_t*)globalref_sym);
627+
value_t scmv = fl_cons(fl_ctx, hd, args);
628+
fl_free_gc_handles(fl_ctx, 1);
629+
return scmv;
630+
}
613631
if (jl_is_long(v) && fits_fixnum(jl_unbox_long(v)))
614632
return fixnum(jl_unbox_long(v));
615633
if (jl_is_ssavalue(v))

src/codegen.cpp

+16-4
Original file line numberDiff line numberDiff line change
@@ -3497,13 +3497,20 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx)
34973497

34983498
Value *bp = NULL, *name, *bp_owner = V_null;
34993499
jl_binding_t *bnd = NULL;
3500-
if (jl_is_symbol(mn)) {
3500+
bool issym = jl_is_symbol(mn);
3501+
bool isglobalref = !issym && jl_is_globalref(mn);
3502+
if (issym || isglobalref) {
3503+
jl_module_t *mod = ctx->module;
3504+
if (isglobalref) {
3505+
mod = jl_globalref_mod(mn);
3506+
mn = (jl_value_t*)jl_globalref_name(mn);
3507+
}
35013508
if (jl_symbol_name((jl_sym_t*)mn)[0] == '@')
35023509
jl_errorf("macro definition not allowed inside a local scope");
35033510
name = literal_pointer_val(mn);
3504-
bnd = jl_get_binding_for_method_def(ctx->module, (jl_sym_t*)mn);
3511+
bnd = jl_get_binding_for_method_def(mod, (jl_sym_t*)mn);
35053512
bp = julia_binding_gv(bnd);
3506-
bp_owner = literal_pointer_val((jl_value_t*)ctx->module);
3513+
bp_owner = literal_pointer_val((jl_value_t*)mod);
35073514
}
35083515
else if (jl_is_slot(mn)) {
35093516
int sl = jl_slot_number(mn)-1;
@@ -3527,10 +3534,15 @@ static jl_cgval_t emit_expr(jl_value_t *expr, jl_codectx_t *ctx)
35273534
}
35283535
else if (head == const_sym) {
35293536
jl_sym_t *sym = (jl_sym_t*)args[0];
3537+
jl_module_t *mod = ctx->module;
3538+
if (jl_is_globalref(sym)) {
3539+
mod = jl_globalref_mod(sym);
3540+
sym = jl_globalref_name(sym);
3541+
}
35303542
if (jl_is_symbol(sym)) {
35313543
JL_FEAT_REQUIRE(ctx, runtime);
35323544
jl_binding_t *bnd = NULL;
3533-
(void)global_binding_pointer(ctx->module, sym, &bnd, true, ctx); assert(bnd);
3545+
(void)global_binding_pointer(mod, sym, &bnd, true, ctx); assert(bnd);
35343546
builder.CreateCall(prepare_call(jldeclareconst_func),
35353547
literal_pointer_val(bnd));
35363548
}

src/interpreter.c

+34-7
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ static jl_value_t *eval(jl_value_t *e, interpreter_state *s)
246246
}
247247
else if (ex->head == method_sym) {
248248
jl_sym_t *fname = (jl_sym_t*)args[0];
249+
if (jl_is_globalref(fname)) {
250+
modu = jl_globalref_mod(fname);
251+
fname = jl_globalref_name(fname);
252+
}
249253
assert(jl_expr_nargs(ex) != 1 || jl_is_symbol(fname));
250254

251255
if (jl_is_symbol(fname)) {
@@ -271,18 +275,29 @@ static jl_value_t *eval(jl_value_t *e, interpreter_state *s)
271275
return jl_nothing;
272276
}
273277
else if (ex->head == const_sym) {
274-
jl_value_t *sym = args[0];
278+
jl_sym_t *sym = (jl_sym_t*)args[0];
279+
if (jl_is_globalref(sym)) {
280+
modu = jl_globalref_mod(sym);
281+
sym = jl_globalref_name(sym);
282+
}
275283
assert(jl_is_symbol(sym));
276-
jl_binding_t *b = jl_get_binding_wr(modu, (jl_sym_t*)sym);
284+
jl_binding_t *b = jl_get_binding_wr(modu, sym);
277285
jl_declare_constant(b);
278286
return (jl_value_t*)jl_nothing;
279287
}
280288
else if (ex->head == global_sym) {
281289
// create uninitialized mutable binding for "global x" decl
282290
// TODO: handle type decls
283-
for (size_t i=0; i < jl_array_len(ex->args); i++) {
284-
assert(jl_is_symbol(args[i]));
285-
jl_get_binding_wr(modu, (jl_sym_t*)args[i]);
291+
size_t i, l = jl_array_len(ex->args);
292+
for (i = 0; i < l; i++) {
293+
jl_sym_t *gsym = (jl_sym_t*)args[i];
294+
jl_module_t *gmodu = modu;
295+
if (jl_is_globalref(gsym)) {
296+
gmodu = jl_globalref_mod(gsym);
297+
gsym = jl_globalref_name(gsym);
298+
}
299+
assert(jl_is_symbol(gsym));
300+
jl_get_binding_wr(gmodu, gsym);
286301
}
287302
return (jl_value_t*)jl_nothing;
288303
}
@@ -296,6 +311,10 @@ static jl_value_t *eval(jl_value_t *e, interpreter_state *s)
296311
jl_datatype_t *dt = NULL;
297312
JL_GC_PUSH4(&para, &super, &temp, &dt);
298313
assert(jl_is_svec(para));
314+
if (jl_is_globalref(name)) {
315+
modu = jl_globalref_mod(name);
316+
name = (jl_value_t*)jl_globalref_name(name);
317+
}
299318
assert(jl_is_symbol(name));
300319
dt = jl_new_abstracttype(name, NULL, (jl_svec_t*)para);
301320
jl_binding_t *b = jl_get_binding_wr(modu, (jl_sym_t*)name);
@@ -328,6 +347,10 @@ static jl_value_t *eval(jl_value_t *e, interpreter_state *s)
328347
jl_value_t *super = NULL, *para = NULL, *vnb = NULL, *temp = NULL;
329348
jl_datatype_t *dt = NULL;
330349
JL_GC_PUSH4(&para, &super, &temp, &dt);
350+
if (jl_is_globalref(name)) {
351+
modu = jl_globalref_mod(name);
352+
name = (jl_value_t*)jl_globalref_name(name);
353+
}
331354
assert(jl_is_symbol(name));
332355
para = eval(args[1], s);
333356
assert(jl_is_svec(para));
@@ -367,13 +390,17 @@ static jl_value_t *eval(jl_value_t *e, interpreter_state *s)
367390
if (inside_typedef)
368391
jl_error("cannot eval a new data type definition while defining another type");
369392
jl_value_t *name = args[0];
370-
assert(jl_is_symbol(name));
371393
jl_value_t *para = eval(args[1], s);
372-
assert(jl_is_svec(para));
373394
jl_value_t *temp = NULL;
374395
jl_value_t *super = NULL;
375396
jl_datatype_t *dt = NULL;
376397
JL_GC_PUSH4(&para, &super, &temp, &dt);
398+
if (jl_is_globalref(name)) {
399+
modu = jl_globalref_mod(name);
400+
name = (jl_value_t*)jl_globalref_name(name);
401+
}
402+
assert(jl_is_symbol(name));
403+
assert(jl_is_svec(para));
377404
temp = eval(args[2], s); // field names
378405
#ifndef NDEBUG
379406
size_t i, l = jl_svec_len(para);

src/julia-syntax.scm

+8
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,14 @@
18001800
(error (string "invalid assignment location \"" (deparse lhs) "\"")))
18011801
(else
18021802
(case (car lhs)
1803+
((globalref)
1804+
;; M.b =
1805+
(let* ((rhs (caddr e))
1806+
(rr (if (or (symbol-like? rhs) (atom? rhs)) rhs (make-ssavalue))))
1807+
`(block
1808+
,.(if (eq? rr rhs) '() `((= ,rr ,(expand-forms rhs))))
1809+
(= ,lhs ,rr)
1810+
(unnecessary ,rr))))
18031811
((|.|)
18041812
;; a.b =
18051813
(let* ((a (cadr lhs))

src/macroexpand.scm

+1-1
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@
423423
(error (cadr form)))
424424
(let ((form (car form))
425425
(m (cdr form)))
426-
;; m is the macro's def module, or #f if def env === use env
426+
;; m is the macro's def module
427427
(rename-symbolic-labels
428428
(julia-expand-macros
429429
(resolve-expansion-vars form m))))))

test/core.jl

+28-1
Original file line numberDiff line numberDiff line change
@@ -3490,7 +3490,7 @@ end
34903490

34913491
# issue 13855
34923492
macro m13855()
3493-
Expr(:localize, :(() -> x))
3493+
Expr(:localize, :(() -> $(esc(:x))))
34943494
end
34953495
@noinline function foo13855(x)
34963496
@m13855()
@@ -4794,3 +4794,30 @@ end
47944794
@test let_Box4()() == 44
47954795
@test let_Box5()() == 46
47964796
@test let_noBox()() == 21
4797+
4798+
module TestModuleAssignment
4799+
using Base.Test
4800+
@eval $(GlobalRef(TestModuleAssignment, :x)) = 1
4801+
@test x == 1
4802+
@eval $(GlobalRef(TestModuleAssignment, :x)) = 2
4803+
@test x == 2
4804+
end
4805+
4806+
# issue #14893
4807+
module M14893
4808+
x = 14893
4809+
macro m14893()
4810+
:x
4811+
end
4812+
function f14893()
4813+
x = 1
4814+
@m14893
4815+
end
4816+
end
4817+
function f14893()
4818+
x = 2
4819+
M14893.@m14893
4820+
end
4821+
4822+
@test f14893() == 14893
4823+
@test M14893.f14893() == 14893

0 commit comments

Comments
 (0)