Skip to content

Commit dc7f3df

Browse files
committed
awesome new bug! added test case
1 parent 7b548e7 commit dc7f3df

File tree

1 file changed

+68
-13
lines changed

1 file changed

+68
-13
lines changed

src/libsyntax/ext/expand.rs

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,6 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
420420
span: span
421421
}
422422
});
423-
let fm = fresh_mark();
424423
// mark before expansion:
425424
let marked_tts = mark_tts(tts,fm);
426425
let marked_ctxt = new_mark(fm,ctxt);
@@ -1533,7 +1532,7 @@ mod test {
15331532
use super::*;
15341533
use ast;
15351534
use ast::{Attribute_, AttrOuter, MetaWord, EMPTY_CTXT};
1536-
use ast_util::{get_sctable, mtwt_resolve, new_rename};
1535+
use ast_util::{get_sctable, mtwt_marksof, mtwt_resolve, new_rename};
15371536
use codemap;
15381537
use codemap::Spanned;
15391538
use parse;
@@ -1709,31 +1708,40 @@ mod test {
17091708
//
17101709
// The comparisons are done post-mtwt-resolve, so we're comparing renamed
17111710
// names; differences in marks don't matter any more.
1712-
type renaming_test = (&'static str, ~[~[uint]]);
1711+
//
1712+
// oog... I also want tests that check "binding-identifier-=?". That is,
1713+
// not just "do these have the same name", but "do they have the same
1714+
// name *and* the same marks"? Understanding this is really pretty painful.
1715+
// in principle, you might want to control this boolean on a per-varref basis,
1716+
// but that would make things even harder to understand, and might not be
1717+
// necessary for thorough testing.
1718+
type renaming_test = (&'static str, ~[~[uint]], bool);
17131719

17141720
#[test]
17151721
fn automatic_renaming () {
1716-
// need some other way to test these...
17171722
let tests : ~[renaming_test] =
17181723
~[// b & c should get new names throughout, in the expr too:
17191724
("fn a() -> int { let b = 13; let c = b; b+c }",
1720-
~[~[0,1],~[2]]),
1725+
~[~[0,1],~[2]], false),
17211726
// both x's should be renamed (how is this causing a bug?)
17221727
("fn main () {let x : int = 13;x;}",
1723-
~[~[0]]),
1728+
~[~[0]], false),
17241729
// the use of b after the + should be renamed, the other one not:
17251730
("macro_rules! f (($x:ident) => (b + $x)) fn a() -> int { let b = 13; f!(b)}",
1726-
~[~[1]]),
1731+
~[~[1]], false),
17271732
// the b before the plus should not be renamed (requires marks)
17281733
("macro_rules! f (($x:ident) => ({let b=9; ($x + b)})) fn a() -> int { f!(b)}",
1729-
~[~[1]]),
1734+
~[~[1]], false),
17301735
// the marks going in and out of letty should cancel, allowing that $x to
17311736
// capture the one following the semicolon.
17321737
// this was an awesome test case, and caught a *lot* of bugs.
17331738
("macro_rules! letty(($x:ident) => (let $x = 15;))
17341739
macro_rules! user(($x:ident) => ({letty!($x); $x}))
17351740
fn main() -> int {user!(z)}",
1736-
~[~[0]])
1741+
~[~[0]], false),
1742+
// can't believe I missed this one : a macro def that refers to a local var:
1743+
("fn main() {let x = 19; macro_rules! getx(()=>(x)); getx!();}",
1744+
~[~[0]], true)
17371745
// FIXME #6994: the next string exposes the bug referred to in issue 6994, so I'm
17381746
// commenting it out.
17391747
// the z flows into and out of two macros (g & f) along one path, and one
@@ -1750,10 +1758,10 @@ mod test {
17501758
}
17511759
}
17521760

1753-
1761+
// run one of the renaming tests
17541762
fn run_renaming_test(t : &renaming_test) {
1755-
let (teststr, bound_connections) = match *t {
1756-
(ref str,ref conns) => (str.to_managed(), conns.clone())
1763+
let (teststr, bound_connections, bound_ident_check) = match *t {
1764+
(ref str,ref conns, bic) => (str.to_managed(), conns.clone(), bic)
17571765
};
17581766
let cr = expand_crate_str(teststr.to_managed());
17591767
// find the bindings:
@@ -1766,15 +1774,18 @@ mod test {
17661774
assert_eq!(bindings.len(),bound_connections.len());
17671775
for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() {
17681776
let binding_name = mtwt_resolve(bindings[binding_idx]);
1777+
let binding_marks = mtwt_marksof(bindings[binding_idx].ctxt,binding_name);
17691778
// shouldmatch can't name varrefs that don't exist:
17701779
assert!((shouldmatch.len() == 0) ||
17711780
(varrefs.len() > *shouldmatch.iter().max().unwrap()));
17721781
for (idx,varref) in varrefs.iter().enumerate() {
17731782
if shouldmatch.contains(&idx) {
17741783
// it should be a path of length 1, and it should
1775-
// be free-identifier=? to the given binding
1784+
// be free-identifier=? or bound-identifier=? to the given binding
17761785
assert_eq!(varref.segments.len(),1);
17771786
let varref_name = mtwt_resolve(varref.segments[0].identifier);
1787+
let varref_marks = mtwt_marksof(varref.segments[0].identifier.ctxt,
1788+
binding_name);
17781789
if (!(varref_name==binding_name)){
17791790
std::io::println("uh oh, should match but doesn't:");
17801791
std::io::println(fmt!("varref: %?",varref));
@@ -1786,6 +1797,10 @@ mod test {
17861797
}
17871798
}
17881799
assert_eq!(varref_name,binding_name);
1800+
if (bound_ident_check) {
1801+
// we need to check the marks, too:
1802+
assert_eq!(varref_marks,binding_marks.clone());
1803+
}
17891804
} else {
17901805
let fail = (varref.segments.len() == 1)
17911806
&& (mtwt_resolve(varref.segments[0].identifier) == binding_name);
@@ -1854,6 +1869,46 @@ mod test {
18541869
};
18551870
}
18561871

1872+
#[test] fn fmt_in_macro_used_inside_module_macro() {
1873+
let crate_str = @"macro_rules! fmt_wrap(($b:expr)=>(fmt!(\"left: %?\", $b)))
1874+
macro_rules! foo_module (() => (mod generated { fn a() { let xx = 147; fmt_wrap!(xx);}}))
1875+
foo_module!()
1876+
";
1877+
let cr = expand_crate_str(crate_str);
1878+
// find the xx binding
1879+
let bindings = @mut ~[];
1880+
visit::walk_crate(&mut new_name_finder(bindings), cr, ());
1881+
let cxbinds : ~[&ast::Ident] =
1882+
bindings.iter().filter(|b|{@"xx" == (ident_to_str(*b))}).collect();
1883+
let cxbind = match cxbinds {
1884+
[b] => b,
1885+
_ => fail!("expected just one binding for ext_cx")
1886+
};
1887+
let resolved_binding = mtwt_resolve(*cxbind);
1888+
// find all the xx varrefs:
1889+
let varrefs = @mut ~[];
1890+
visit::walk_crate(&mut new_path_finder(varrefs), cr, ());
1891+
// the xx binding should bind all of the xx varrefs:
1892+
for (idx,v) in varrefs.iter().filter(|p|{ p.segments.len() == 1
1893+
&& (@"xx" == (ident_to_str(&p.segments[0].identifier)))
1894+
}).enumerate() {
1895+
if (mtwt_resolve(v.segments[0].identifier) != resolved_binding) {
1896+
std::io::println("uh oh, xx binding didn't match xx varref:");
1897+
std::io::println(fmt!("this is xx varref # %?",idx));
1898+
std::io::println(fmt!("binding: %?",cxbind));
1899+
std::io::println(fmt!("resolves to: %?",resolved_binding));
1900+
std::io::println(fmt!("varref: %?",v.segments[0].identifier));
1901+
std::io::println(fmt!("resolves to: %?",mtwt_resolve(v.segments[0].identifier)));
1902+
let table = get_sctable();
1903+
std::io::println("SC table:");
1904+
for (idx,val) in table.table.iter().enumerate() {
1905+
std::io::println(fmt!("%4u : %?",idx,val));
1906+
}
1907+
}
1908+
assert_eq!(mtwt_resolve(v.segments[0].identifier),resolved_binding);
1909+
};
1910+
}
1911+
18571912
#[test]
18581913
fn pat_idents(){
18591914
let pat = string_to_pat(@"(a,Foo{x:c @ (b,9),y:Bar(4,d)})");

0 commit comments

Comments
 (0)