about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorJohn Clements <clements@racket-lang.org>2014-06-26 16:49:13 -0700
committerJohn Clements <clements@racket-lang.org>2014-06-27 22:08:57 -0700
commit4b46c700f4bf04331b1858e7fe3c363c0451c4cb (patch)
tree2acbb41587d95589da4616d31776f7bbf59ac24b /src/libsyntax
parent7bad96e742b187b671500702bccb37ab1724bae5 (diff)
downloadrust-4b46c700f4bf04331b1858e7fe3c363c0451c4cb.tar.gz
rust-4b46c700f4bf04331b1858e7fe3c363c0451c4cb.zip
hygiene for match-bound vars now implemented
Closes #9384
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/expand.rs57
1 files changed, 33 insertions, 24 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 941a4bb68c2..c2bb2cd7347 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -608,7 +608,7 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander)
                         span: span,
                         source: source,
                     } = **local;
-                    // expand the pat (it might contain exprs... #:(o)>
+                    // expand the pat (it might contain macro uses):
                     let expanded_pat = fld.fold_pat(pat);
                     // find the pat_idents in the pattern:
                     // 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 mut new_pending_renames =
                         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 mut rename_fld =
-                            IdentRenamer{renames: &mut new_pending_renames};
-                        // rewrite the pattern using the new names (the old
-                        // ones have already been applied):
+                        // nested binding to allow borrow to expire:
+                        let mut rename_fld = IdentRenamer{renames: &mut new_pending_renames};
                         rename_fld.fold_pat(expanded_pat)
                     };
                     // 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 {
-    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");
     }
     // all of the pats must have the same set of bindings, so use the
     // 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
     // into a separate function:
-    let expanded_pat = fld.fold_pat(*first_pat);
-    let mut new_pending_renames = Vec::new();
-    for ident in pattern_bindings(expanded_pat).iter() {
-        let new_name = fresh_name(ident);
-        new_pending_renames.push((*ident,new_name));
-    }
-    let rewritten_pat = {
-        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)
-    };
+    let idents = pattern_bindings(*first_pat);
+    let mut new_pending_renames =
+        idents.iter().map(|id| (*id,fresh_name(id))).collect();
+    // rewrite all of the patterns using the new names (the old
+    // ones have already been applied). Note that we depend here
+    // on the guarantee that after expansion, there can't be any
+    // Path expressions (a.k.a. varrefs) left in the pattern. If
+    // this were false, we'd need to apply this renaming only to
+    // the bindings, and not to the varrefs, using a more targeted
+    // fold-er.
+    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 {
         attrs: arm.attrs.iter().map(|x| fld.fold_attribute(*x)).collect(),
-        pats: arm.pats.iter().map(|x| fld.fold_pat(*x)).collect(),
-        guard: arm.guard.map(|x| fld.fold_expr(x)),
-        body: fld.fold_expr(arm.body),
+        pats: rewritten_pats,
+        guard: rewritten_guard,
+        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
+// to every identifier, including both bindings and varrefs
+// (and lots of things that will turn out to be neither)
 pub struct IdentRenamer<'a> {
     renames: &'a mut RenameList,
 }
@@ -1335,8 +1344,8 @@ mod test {
                                                      invalid_name);
                     if !(varref_name==binding_name) {
                         println!("uh oh, should match but doesn't:");
-                        println!("varref: {:?}",varref);
-                        println!("binding: {:?}", *bindings.get(binding_idx));
+                        println!("varref #{:?}: {:?}",idx, varref);
+                        println!("binding #{:?}: {:?}", binding_idx, *bindings.get(binding_idx));
                         mtwt::with_sctable(|x| mtwt::display_sctable(x));
                     }
                     assert_eq!(varref_name,binding_name);