From e6f1010ef967123bcc1046383d228dbae78bcde4 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Mon, 7 Jun 2021 06:29:07 -0700 Subject: expander: expand must only ignores unbound warnings. The expand function must not muffle all deferred warnings. That causes the problem that a form like (inc var a.bar) fails to produce a warning due to bar not being the slot of any structure. The expand function must only muffle warnings about undefined functions and variables. * eval.c (muffle_unbound_warning): New static function. (no_warn_expand): Use muffle_unbound_warning as handler, rather than uw_muffle_warning. * tests/012/struct.tl: Fix two test cases here which test the expand function using a form that references a nonexistent slot. These now generate a warning, so we use the slot name b rather than d, which is defined. * txr.1: Documented change to expand. --- eval.c | 21 ++++++++++++++++++++- tests/012/struct.tl | 8 ++++---- txr.1 | 15 ++++++++++++++- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/eval.c b/eval.c index bf0dc246..2d840160 100644 --- a/eval.c +++ b/eval.c @@ -5088,12 +5088,31 @@ val expand(val form, val menv) return ret; } +static val muffle_unbound_warning(val exc, struct args *args) +{ + (void) exc; + + args_normalize_least(args, 2); + + if (args->fill >= 2) { + val tag = args->arg[1]; + + if (consp(tag)) { + val type = car(tag); + if (type == var_s || type == fun_s || type == sym_s) + uw_rthrow(continue_s, nil); + } + } + + return nil; +} + static val no_warn_expand(val form, val menv) { val ret; uw_frame_t uw_handler; uw_push_handler(&uw_handler, cons(defr_warning_s, nil), - func_n1v(uw_muffle_warning)); + func_n1v(muffle_unbound_warning)); ret = expand(form, menv); uw_pop_frame(&uw_handler); return ret; diff --git a/tests/012/struct.tl b/tests/012/struct.tl index 57234913..3f03552d 100644 --- a/tests/012/struct.tl +++ b/tests/012/struct.tl @@ -43,10 +43,10 @@ (stest (ignwarn (expand 's.(a b c))) "(call (slot s 'a)\n \ \ s b c)") -(test (expand 's.[a].d) - (slot [(slot s 'a) s] 'd)) -(test (expand 's.[a b c].d) - (slot [(slot s 'a) s b c] 'd)) +(test (expand 's.[a].b) + (slot [(slot s 'a) s] 'b)) +(test (expand 's.[a b c].b) + (slot [(slot s 'a) s b c] 'b)) (set *gensym-counter* 0) (stest (ignwarn (expand 's.(a).d)) "(slot (call (slot s 'a)\n \ diff --git a/txr.1 b/txr.1 index 88bfebfe..9cb01efb 100644 --- a/txr.1 +++ b/txr.1 @@ -36903,7 +36903,20 @@ and .code expand* is that .code expand -suppresses any warning exceptions that are issued during expansion. +suppresses expansion-time deferred warnings (exceptions of type +.codn defr-warning ), +issued for unbound variables or functions. +To suppress a warning means to intercept the warning exception with a handler +which throws a +.code continue +exception to resume processing. +What this requirement means is that if unbound functions or variables +occur in the +.meta form +being expanded by expand, the warning is effectively squelched. Rationale: +.code expand +is may be used by macros for expanding fragments which contain references to +variables or functions which are not defined in those fragments. .coNP Function @ expand-with-free-refs .synb -- cgit v1.2.3