awesome new bug! added test case
This commit is contained in:
parent
7b548e7180
commit
dc7f3df27f
1 changed files with 68 additions and 13 deletions
|
|
@ -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)})");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue