diff options
| author | John Clements <clements@racket-lang.org> | 2013-07-12 18:35:47 -0700 |
|---|---|---|
| committer | John Clements <clements@racket-lang.org> | 2013-09-06 13:35:12 -0700 |
| commit | dc7f3df27fd17b41b3448f461138947db4c9bab2 (patch) | |
| tree | e5e4f6db426356fb44c6bb0bcec6f3392d2f2f50 /src/libsyntax/ext | |
| parent | 7b548e71806b735a215f7dba26a20771c4f924bd (diff) | |
| download | rust-dc7f3df27fd17b41b3448f461138947db4c9bab2.tar.gz rust-dc7f3df27fd17b41b3448f461138947db4c9bab2.zip | |
awesome new bug! added test case
Diffstat (limited to 'src/libsyntax/ext')
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 81 |
1 files changed, 68 insertions, 13 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 120f75406c7..3a5b9f2f7c6 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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 @@ mod test { // // 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 @@ mod test { } } - + // 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 @@ mod 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 @@ mod 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 @@ mod test { }; } + #[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)})"); |
