1
Fork 0

hygiene for match-bound vars now implemented

Closes #9384
This commit is contained in:
John Clements 2014-06-26 16:49:13 -07:00
parent 7bad96e742
commit 4b46c700f4

View file

@ -608,7 +608,7 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
span: span, span: span,
source: source, source: source,
} = **local; } = **local;
// expand the pat (it might contain exprs... #:(o)> // expand the pat (it might contain macro uses):
let expanded_pat = fld.fold_pat(pat); let expanded_pat = fld.fold_pat(pat);
// find the pat_idents in the pattern: // find the pat_idents in the pattern:
// oh dear heaven... this is going to include the enum // oh dear heaven... this is going to include the enum
@ -618,11 +618,11 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
let idents = pattern_bindings(expanded_pat); let idents = pattern_bindings(expanded_pat);
let mut new_pending_renames = let mut new_pending_renames =
idents.iter().map(|ident| (*ident, fresh_name(ident))).collect(); idents.iter().map(|ident| (*ident, fresh_name(ident))).collect();
// rewrite the pattern using the new names (the old
// ones have already been applied):
let rewritten_pat = { let rewritten_pat = {
let mut rename_fld = // nested binding to allow borrow to expire:
IdentRenamer{renames: &mut new_pending_renames}; let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames};
// rewrite the pattern using the new names (the old
// ones have already been applied):
rename_fld.fold_pat(expanded_pat) rename_fld.fold_pat(expanded_pat)
}; };
// add them to the existing pending renames: // add them to the existing pending renames:
@ -655,31 +655,38 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
} }
fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm { fn expand_arm(arm: &ast::Arm, fld: &mut MacroExpander) -> ast::Arm {
if arm.pats.len() == 0 { // expand pats... they might contain macro uses:
let expanded_pats : Vec<Gc<ast::Pat>> = arm.pats.iter().map(|pat| fld.fold_pat(*pat)).collect();
if expanded_pats.len() == 0 {
fail!("encountered match arm with 0 patterns"); fail!("encountered match arm with 0 patterns");
} }
// all of the pats must have the same set of bindings, so use the // all of the pats must have the same set of bindings, so use the
// first one to extract them and generate new names: // first one to extract them and generate new names:
let first_pat = arm.pats.get(0); let first_pat = expanded_pats.get(0);
// code duplicated from 'let', above. Perhaps this can be lifted // code duplicated from 'let', above. Perhaps this can be lifted
// into a separate function: // into a separate function:
let expanded_pat = fld.fold_pat(*first_pat); let idents = pattern_bindings(*first_pat);
let mut new_pending_renames = Vec::new(); let mut new_pending_renames =
for ident in pattern_bindings(expanded_pat).iter() { idents.iter().map(|id| (*id,fresh_name(id))).collect();
let new_name = fresh_name(ident); // rewrite all of the patterns using the new names (the old
new_pending_renames.push((*ident,new_name)); // ones have already been applied). Note that we depend here
} // on the guarantee that after expansion, there can't be any
let rewritten_pat = { // Path expressions (a.k.a. varrefs) left in the pattern. If
let mut rename_fld = IdentRenamer{renames:&mut new_pending_renames}; // this were false, we'd need to apply this renaming only to
// rewrite the pattern using the new names (the old // the bindings, and not to the varrefs, using a more targeted
// ones have already been applied): // fold-er.
rename_fld.fold_pat(expanded_pat) let mut rename_fld = IdentRenamer{renames:&mut new_pending_renames};
}; let rewritten_pats =
expanded_pats.iter().map(|pat| rename_fld.fold_pat(*pat)).collect();
// apply renaming and then expansion to the guard and the body:
let rewritten_guard =
arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body));
ast::Arm { ast::Arm {
attrs: arm.attrs.iter().map(|x| fld.fold_attribute(*x)).collect(), attrs: arm.attrs.iter().map(|x| fld.fold_attribute(*x)).collect(),
pats: arm.pats.iter().map(|x| fld.fold_pat(*x)).collect(), pats: rewritten_pats,
guard: arm.guard.map(|x| fld.fold_expr(x)), guard: rewritten_guard,
body: fld.fold_expr(arm.body), body: rewritten_body,
} }
} }
@ -851,6 +858,8 @@ fn expand_pat(p: Gc<ast::Pat>, fld: &mut MacroExpander) -> Gc<ast::Pat> {
} }
// a tree-folder that applies every rename in its (mutable) list // a tree-folder that applies every rename in its (mutable) list
// to every identifier, including both bindings and varrefs
// (and lots of things that will turn out to be neither)
pub struct IdentRenamer<'a> { pub struct IdentRenamer<'a> {
renames: &'a mut RenameList, renames: &'a mut RenameList,
} }
@ -1335,8 +1344,8 @@ mod test {
invalid_name); invalid_name);
if !(varref_name==binding_name) { if !(varref_name==binding_name) {
println!("uh oh, should match but doesn't:"); println!("uh oh, should match but doesn't:");
println!("varref: {:?}",varref); println!("varref #{:?}: {:?}",idx, varref);
println!("binding: {:?}", *bindings.get(binding_idx)); println!("binding #{:?}: {:?}", binding_idx, *bindings.get(binding_idx));
mtwt::with_sctable(|x| mtwt::display_sctable(x)); mtwt::with_sctable(|x| mtwt::display_sctable(x));
} }
assert_eq!(varref_name,binding_name); assert_eq!(varref_name,binding_name);