]> git.lizzy.rs Git - rust.git/commitdiff
awesome new bug! added test case
authorJohn Clements <clements@racket-lang.org>
Sat, 13 Jul 2013 01:35:47 +0000 (18:35 -0700)
committerJohn Clements <clements@racket-lang.org>
Fri, 6 Sep 2013 20:35:12 +0000 (13:35 -0700)
src/libsyntax/ext/expand.rs

index 120f75406c7bc03be3e9cf00e042201b4a915b21..3a5b9f2f7c674c2832868041170e8103291d5955 100644 (file)
@@ -420,7 +420,6 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
                     span: span
                 }
             });
-            let fm = fresh_mark();
             // mark before expansion:
             let marked_tts = mark_tts(tts,fm);
             let marked_ctxt = new_mark(fm,ctxt);
@@ -1533,7 +1532,7 @@ mod test {
     use super::*;
     use ast;
     use ast::{Attribute_, AttrOuter, MetaWord, EMPTY_CTXT};
-    use ast_util::{get_sctable, mtwt_resolve, new_rename};
+    use ast_util::{get_sctable, mtwt_marksof, mtwt_resolve, new_rename};
     use codemap;
     use codemap::Spanned;
     use parse;
@@ -1709,31 +1708,40 @@ fn expand_crate_str(crate_str: @str) -> @ast::Crate {
     //
     // The comparisons are done post-mtwt-resolve, so we're comparing renamed
     // names; differences in marks don't matter any more.
-    type renaming_test = (&'static str, ~[~[uint]]);
+    //
+    // oog... I also want tests that check "binding-identifier-=?". That is,
+    // not just "do these have the same name", but "do they have the same
+    // name *and* the same marks"? Understanding this is really pretty painful.
+    // in principle, you might want to control this boolean on a per-varref basis,
+    // but that would make things even harder to understand, and might not be
+    // necessary for thorough testing.
+    type renaming_test = (&'static str, ~[~[uint]], bool);
 
     #[test]
     fn automatic_renaming () {
-        // need some other way to test these...
         let tests : ~[renaming_test] =
             ~[// b & c should get new names throughout, in the expr too:
                 ("fn a() -> int { let b = 13; let c = b; b+c }",
-                 ~[~[0,1],~[2]]),
+                 ~[~[0,1],~[2]], false),
                 // both x's should be renamed (how is this causing a bug?)
                 ("fn main () {let x : int = 13;x;}",
-                 ~[~[0]]),
+                 ~[~[0]], false),
                 // the use of b after the + should be renamed, the other one not:
                 ("macro_rules! f (($x:ident) => (b + $x)) fn a() -> int { let b = 13; f!(b)}",
-                 ~[~[1]]),
+                 ~[~[1]], false),
                 // the b before the plus should not be renamed (requires marks)
                 ("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})) fn a() -> int { f!(b)}",
-                 ~[~[1]]),
+                 ~[~[1]], false),
                 // the marks going in and out of letty should cancel, allowing that $x to
                 // capture the one following the semicolon.
                 // this was an awesome test case, and caught a *lot* of bugs.
                 ("macro_rules! letty(($x:ident) => (let $x = 15;))
                   macro_rules! user(($x:ident) => ({letty!($x); $x}))
                   fn main() -> int {user!(z)}",
-                 ~[~[0]])
+                 ~[~[0]], false),
+                // can't believe I missed this one : a macro def that refers to a local var:
+                ("fn main() {let x = 19; macro_rules! getx(()=>(x)); getx!();}",
+                ~[~[0]], true)
                 // FIXME #6994: the next string exposes the bug referred to in issue 6994, so I'm
                 // commenting it out.
                 // the z flows into and out of two macros (g & f) along one path, and one
@@ -1750,10 +1758,10 @@ fn main() -> int {user!(z)}",
         }
     }
 
-
+    // run one of the renaming tests
     fn run_renaming_test(t : &renaming_test) {
-        let (teststr, bound_connections) = match *t {
-            (ref str,ref conns) => (str.to_managed(), conns.clone())
+        let (teststr, bound_connections, bound_ident_check) = match *t {
+            (ref str,ref conns, bic) => (str.to_managed(), conns.clone(), bic)
         };
         let cr = expand_crate_str(teststr.to_managed());
         // find the bindings:
@@ -1766,15 +1774,18 @@ fn run_renaming_test(t : &renaming_test) {
         assert_eq!(bindings.len(),bound_connections.len());
         for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
             let binding_name = mtwt_resolve(bindings[binding_idx]);
+            let binding_marks = mtwt_marksof(bindings[binding_idx].ctxt,binding_name);
             // shouldmatch can't name varrefs that don't exist:
             assert!((shouldmatch.len() == 0) ||
                     (varrefs.len() > *shouldmatch.iter().max().unwrap()));
             for (idx,varref) in varrefs.iter().enumerate() {
                 if shouldmatch.contains(&idx) {
                     // it should be a path of length 1, and it should
-                    // be free-identifier=? to the given binding
+                    // be free-identifier=? or bound-identifier=? to the given binding
                     assert_eq!(varref.segments.len(),1);
                     let varref_name = mtwt_resolve(varref.segments[0].identifier);
+                    let varref_marks = mtwt_marksof(varref.segments[0].identifier.ctxt,
+                                                    binding_name);
                     if (!(varref_name==binding_name)){
                         std::io::println("uh oh, should match but doesn't:");
                         std::io::println(fmt!("varref: %?",varref));
@@ -1786,6 +1797,10 @@ fn run_renaming_test(t : &renaming_test) {
                         }
                     }
                     assert_eq!(varref_name,binding_name);
+                    if (bound_ident_check) {
+                        // we need to check the marks, too:
+                        assert_eq!(varref_marks,binding_marks.clone());
+                    }
                 } else {
                     let fail = (varref.segments.len() == 1)
                         && (mtwt_resolve(varref.segments[0].identifier) == binding_name);
@@ -1854,6 +1869,46 @@ fn quote_ext_cx_test(crate_str : @str) {
         };
     }
 
+    #[test] fn fmt_in_macro_used_inside_module_macro() {
+        let crate_str = @"macro_rules! fmt_wrap(($b:expr)=>(fmt!(\"left: %?\", $b)))
+macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}))
+foo_module!()
+";
+        let cr = expand_crate_str(crate_str);
+        // find the xx binding
+        let bindings = @mut ~[];
+        visit::walk_crate(&mut new_name_finder(bindings), cr, ());
+        let cxbinds : ~[&ast::Ident] =
+            bindings.iter().filter(|b|{@"xx" == (ident_to_str(*b))}).collect();
+        let cxbind = match cxbinds {
+            [b] => b,
+            _ => fail!("expected just one binding for ext_cx")
+        };
+        let resolved_binding = mtwt_resolve(*cxbind);
+        // find all the xx varrefs:
+        let varrefs = @mut ~[];
+        visit::walk_crate(&mut new_path_finder(varrefs), cr, ());
+        // the xx binding should bind all of the xx varrefs:
+        for (idx,v) in varrefs.iter().filter(|p|{ p.segments.len() == 1
+                                          && (@"xx" == (ident_to_str(&p.segments[0].identifier)))
+                                     }).enumerate() {
+            if (mtwt_resolve(v.segments[0].identifier) != resolved_binding) {
+                std::io::println("uh oh, xx binding didn't match xx varref:");
+                std::io::println(fmt!("this is xx varref # %?",idx));
+                std::io::println(fmt!("binding: %?",cxbind));
+                std::io::println(fmt!("resolves to: %?",resolved_binding));
+                std::io::println(fmt!("varref: %?",v.segments[0].identifier));
+                std::io::println(fmt!("resolves to: %?",mtwt_resolve(v.segments[0].identifier)));
+                let table = get_sctable();
+                std::io::println("SC table:");
+                for (idx,val) in table.table.iter().enumerate() {
+                    std::io::println(fmt!("%4u : %?",idx,val));
+                }
+            }
+            assert_eq!(mtwt_resolve(v.segments[0].identifier),resolved_binding);
+        };
+    }
+
     #[test]
     fn pat_idents(){
         let pat = string_to_pat(@"(a,Foo{x:c @ (b,9),y:Bar(4,d)})");