diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 0d3586266e869..0dafc412de3e1 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4177,7 +4177,7 @@ impl Resolver { fn binding_mode_map(&mut self, pat: @Pat) -> BindingMap { let mut result = HashMap::new(); pat_bindings(self.def_map, pat, |binding_mode, _id, sp, path| { - let name = mtwt::resolve(path_to_ident(path)); + let name = mtwt::resolve(path_to_ident(path), PlainIdent); result.insert(name, binding_info {span: sp, binding_mode: binding_mode}); @@ -4412,7 +4412,7 @@ impl Resolver { // what you want). let ident = path.segments.get(0).identifier; - let renamed = mtwt::resolve(ident); + let renamed = mtwt::resolve(ident, PlainIdent); match self.resolve_bare_identifier_pattern(ident) { FoundStructOrEnumVariant(def, lp) @@ -4966,7 +4966,7 @@ impl Resolver { let search_result; match namespace { ValueNS => { - let renamed = mtwt::resolve(ident); + let renamed = mtwt::resolve(ident, PlainIdent); let mut value_ribs = self.value_ribs.borrow_mut(); search_result = self.search_ribs(value_ribs.get(), renamed, @@ -5214,7 +5214,7 @@ impl Resolver { let rib = label_ribs.get()[label_ribs.get().len() - 1]; let mut bindings = rib.bindings.borrow_mut(); - let renamed = mtwt::resolve(label); + let renamed = mtwt::resolve(label, LifetimeIdent); bindings.get().insert(renamed, def_like); } @@ -5226,7 +5226,7 @@ impl Resolver { ExprBreak(Some(label)) | ExprAgain(Some(label)) => { let mut label_ribs = self.label_ribs.borrow_mut(); - let renamed = mtwt::resolve(label); + let renamed = mtwt::resolve(label, LifetimeIdent); match self.search_ribs(label_ribs.get(), renamed, expr.span) { None => self.resolve_error(expr.span, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 544d9f2d66935..c0e8c199e175c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -75,6 +75,17 @@ impl Eq for Ident { } } +// This can not be more fine-grained because of loop label. It starts +// as a `token::LIFETIME` then becomes part of `ExprLoop`, `ExprForLoop`, +// `ExprBreak` or `ExprAgain` and is represented as an `ast::Ident`, not +// an `ast::Lifetime` as others do. Even so, it is still considered to +// be one of LifetimeIdent. +#[deriving(Clone, Eq, Encodable, Decodable, Hash)] +pub enum IdentKind { + PlainIdent, + LifetimeIdent +} + /// A SyntaxContext represents a chain of macro-expandings /// and renamings. Each macro expansion corresponds to /// a fresh uint diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 79068d4046965..44e364ff965ea 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -148,20 +148,24 @@ pub struct BlockInfo { // should macros escape from this scope? macros_escape: bool, // what are the pending renames? - pending_renames: RenameList, + pending_renames: RenameLists, } impl BlockInfo { pub fn new() -> BlockInfo { BlockInfo { macros_escape: false, - pending_renames: Vec::new(), + pending_renames: RenameLists { plain: Vec::new(), lifetime: Vec::new() }, } } } // a list of ident->name renamings pub type RenameList = Vec<(ast::Ident, Name)>; +pub struct RenameLists { + plain: RenameList, + lifetime: RenameList +} // The base map of methods for expanding syntax extension // AST nodes into full ASTs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 8b23de235b804..5d9adcba3a1c7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -11,7 +11,7 @@ use ast::{P, Block, Crate, DeclLocal, ExprMac}; use ast::{Local, Ident, MacInvocTT}; use ast::{ItemMac, Mrk, Stmt, StmtDecl, StmtMac, StmtExpr, StmtSemi}; -use ast::TokenTree; +use ast::{IdentKind, LifetimeIdent, PlainIdent, TokenTree}; use ast; use ext::mtwt; use ext::build::AstBuilder; @@ -228,15 +228,15 @@ fn expand_loop_block(loop_block: P, // syntax context otherwise an unrelated `break` or `continue` in // the same context will pick that up in the deferred renaming pass // and be renamed incorrectly. - let mut rename_list = vec!(rename); + let mut rename_list = RenameLists { plain: Vec::new(), lifetime: vec!(rename)}; let mut rename_fld = renames_to_fold(&mut rename_list); - let renamed_ident = rename_fld.fold_ident(label); + let renamed_ident = rename_fld.fold_ident(label, LifetimeIdent); // The rename *must* be added to the enclosed syntax context for // `break` or `continue` to pick up because by definition they are // in a block enclosed by loop head. fld.extsbox.push_frame(); - fld.extsbox.info().pending_renames.push(rename); + fld.extsbox.info().pending_renames.lifetime.push(rename); let expanded_block = expand_block_elts(loop_block, fld); fld.extsbox.pop_frame(); @@ -627,10 +627,11 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander) let mut name_finder = new_name_finder(Vec::new()); name_finder.visit_pat(expanded_pat,()); // generate fresh names, push them to a new pending list - let mut new_pending_renames = Vec::new(); + let mut new_pending_renames = RenameLists { plain: Vec::new(), + lifetime: Vec::new() }; for ident in name_finder.ident_accumulator.iter() { let new_name = fresh_name(ident); - new_pending_renames.push((*ident,new_name)); + new_pending_renames.plain.push((*ident,new_name)); } let rewritten_pat = { let mut rename_fld = @@ -640,7 +641,8 @@ fn expand_non_macro_stmt(s: &Stmt, fld: &mut MacroExpander) rename_fld.fold_pat(expanded_pat) }; // add them to the existing pending renames: - fld.extsbox.info().pending_renames.push_all_move(new_pending_renames); + fld.extsbox.info().pending_renames + .plain.push_all_move(new_pending_renames.plain); // also, don't forget to expand the init: let new_init_opt = init.map(|e| fld.fold_expr(e)); let rewritten_local = @@ -760,13 +762,17 @@ pub fn expand_block_elts(b: &Block, fld: &mut MacroExpander) -> P { } pub struct IdentRenamer<'a> { - renames: &'a mut RenameList, + renames: &'a mut RenameLists, } impl<'a> Folder for IdentRenamer<'a> { - fn fold_ident(&mut self, id: Ident) -> Ident { - let new_ctxt = self.renames.iter().fold(id.ctxt, |ctxt, &(from, to)| { - mtwt::new_rename(from, to, ctxt) + fn fold_ident(&mut self, id: Ident, ns: IdentKind) -> Ident { + let rs = match ns { + PlainIdent => &self.renames.plain, + LifetimeIdent => &self.renames.lifetime + }; + let new_ctxt = rs.iter().fold(id.ctxt, |ctxt, &(from, to)| { + mtwt::new_rename(from, to, ctxt, ns) }); Ident { name: id.name, @@ -777,7 +783,7 @@ impl<'a> Folder for IdentRenamer<'a> { // given a mutable list of renames, return a tree-folder that applies those // renames. -pub fn renames_to_fold<'a>(renames: &'a mut RenameList) -> IdentRenamer<'a> { +pub fn renames_to_fold<'a>(renames: &'a mut RenameLists) -> IdentRenamer<'a> { IdentRenamer { renames: renames, } @@ -849,10 +855,10 @@ pub fn expand_crate(parse_sess: @parse::ParseSess, struct Marker { mark: Mrk } impl Folder for Marker { - fn fold_ident(&mut self, id: Ident) -> Ident { + fn fold_ident(&mut self, id: Ident, ns: IdentKind) -> Ident { ast::Ident { name: id.name, - ctxt: mtwt::new_mark(self.mark, id.ctxt) + ctxt: mtwt::new_mark(self.mark, id.ctxt, ns) } } fn fold_mac(&mut self, m: &ast::Mac) -> ast::Mac { @@ -860,7 +866,7 @@ impl Folder for Marker { MacInvocTT(ref path, ref tts, ctxt) => { MacInvocTT(self.fold_path(path), fold_tts(tts.as_slice(), self), - mtwt::new_mark(self.mark, ctxt)) + mtwt::new_mark(self.mark, ctxt, PlainIdent)) } }; Spanned { @@ -1148,8 +1154,9 @@ mod test { // must be one check clause for each binding: assert_eq!(bindings.len(),bound_connections.len()); for (binding_idx,shouldmatch) in bound_connections.iter().enumerate() { - let binding_name = mtwt::resolve(*bindings.get(binding_idx)); - let binding_marks = mtwt::marksof(bindings.get(binding_idx).ctxt, invalid_name); + let binding_name = mtwt::resolve(*bindings.get(binding_idx), ast::PlainIdent); + let binding_marks = mtwt::marksof(bindings.get(binding_idx).ctxt, + invalid_name, ast::PlainIdent); // shouldmatch can't name varrefs that don't exist: assert!((shouldmatch.len() == 0) || (varrefs.len() > *shouldmatch.iter().max().unwrap())); @@ -1160,17 +1167,18 @@ mod test { assert_eq!(varref.segments.len(),1); let varref_name = mtwt::resolve(varref.segments .get(0) - .identifier); + .identifier, + ast::PlainIdent); let varref_marks = mtwt::marksof(varref.segments .get(0) .identifier .ctxt, - invalid_name); + invalid_name, ast::PlainIdent); if !(varref_name==binding_name) { println!("uh oh, should match but doesn't:"); println!("varref: {:?}",varref); println!("binding: {:?}", *bindings.get(binding_idx)); - mtwt::with_sctable(|x| mtwt::display_sctable(x)); + mtwt::with_sctable(ast::PlainIdent, |x| mtwt::display_sctable(x)); } assert_eq!(varref_name,binding_name); if bound_ident_check { @@ -1180,7 +1188,7 @@ mod test { } } else { let fail = (varref.segments.len() == 1) - && (mtwt::resolve(varref.segments.get(0).identifier) + && (mtwt::resolve(varref.segments.get(0).identifier, ast::PlainIdent) == binding_name); // temp debugging: if fail { @@ -1197,7 +1205,7 @@ mod test { varref.segments.get(0).identifier.name, string.get()); println!("binding: {:?}", *bindings.get(binding_idx)); - mtwt::with_sctable(|x| mtwt::display_sctable(x)); + mtwt::with_sctable(ast::PlainIdent, |x| mtwt::display_sctable(x)); } assert!(!fail); } @@ -1227,7 +1235,7 @@ foo_module!() [b] => b, _ => fail!("expected just one binding for ext_cx") }; - let resolved_binding = mtwt::resolve(*cxbind); + let resolved_binding = mtwt::resolve(*cxbind, ast::PlainIdent); // find all the xx varrefs: let mut path_finder = new_path_finder(Vec::new()); visit::walk_crate(&mut path_finder, &cr, ()); @@ -1238,17 +1246,17 @@ foo_module!() p.segments.len() == 1 && "xx" == token::get_ident(p.segments.get(0).identifier).get() }).enumerate() { - if mtwt::resolve(v.segments.get(0).identifier) != resolved_binding { + if mtwt::resolve(v.segments.get(0).identifier, ast::PlainIdent) != resolved_binding { println!("uh oh, xx binding didn't match xx varref:"); println!("this is xx varref \\# {:?}",idx); println!("binding: {:?}",cxbind); println!("resolves to: {:?}",resolved_binding); println!("varref: {:?}",v.segments.get(0).identifier); println!("resolves to: {:?}", - mtwt::resolve(v.segments.get(0).identifier)); - mtwt::with_sctable(|x| mtwt::display_sctable(x)); + mtwt::resolve(v.segments.get(0).identifier, ast::PlainIdent)); + mtwt::with_sctable(ast::PlainIdent, |x| mtwt::display_sctable(x)); } - assert_eq!(mtwt::resolve(v.segments.get(0).identifier), + assert_eq!(mtwt::resolve(v.segments.get(0).identifier, ast::PlainIdent), resolved_binding); }; } diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index b0ed215f3e103..df3e312368d74 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -15,7 +15,8 @@ //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216. //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093 -use ast::{Ident, Mrk, Name, SyntaxContext}; +use ast::{Ident, IdentKind, PlainIdent, LifetimeIdent}; +use ast::{Mrk, Name, SyntaxContext}; use std::cell::RefCell; use std::local_data; @@ -57,8 +58,8 @@ pub enum SyntaxContext_ { } /// Extend a syntax context with a given mark -pub fn new_mark(m: Mrk, tail: SyntaxContext) -> SyntaxContext { - with_sctable(|table| new_mark_internal(m, tail, table)) +pub fn new_mark(m: Mrk, tail: SyntaxContext, ns: IdentKind) -> SyntaxContext { + with_sctable(ns, |table| new_mark_internal(m, tail, table)) } // Extend a syntax context with a given mark and table @@ -73,8 +74,9 @@ fn new_mark_internal(m: Mrk, tail: SyntaxContext, table: &SCTable) -> SyntaxCont /// Extend a syntax context with a given rename pub fn new_rename(id: Ident, to:Name, - tail: SyntaxContext) -> SyntaxContext { - with_sctable(|table| new_rename_internal(id, to, tail, table)) + tail: SyntaxContext, + ns: IdentKind) -> SyntaxContext { + with_sctable(ns, |table| new_rename_internal(id, to, tail, table)) } // Extend a syntax context with a given rename and sctable @@ -90,20 +92,32 @@ fn new_rename_internal(id: Ident, *rename_memo.get().find_or_insert_with(key, new_ctxt) } +struct SCTables { + plain: SCTable, + lifetime: SCTable, +} + /// Fetch the SCTable from TLS, create one if it doesn't yet exist. -pub fn with_sctable(op: |&SCTable| -> T) -> T { - local_data_key!(sctable_key: Rc) +pub fn with_sctable(ns: IdentKind, + op: |&SCTable| -> T) -> T { + local_data_key!(sctable_key: Rc) local_data::get(sctable_key, |opt_ts| { - let table = match opt_ts { + let tables = match opt_ts { None => { - let ts = Rc::new(new_sctable_internal()); + let ts = Rc::new(SCTables { + plain: new_sctable_internal(), + lifetime: new_sctable_internal(), + }); local_data::set(sctable_key, ts.clone()); ts } Some(ts) => ts.clone() }; - op(table.borrow()) + match ns { + PlainIdent => op(&tables.borrow().plain), + LifetimeIdent => op(&tables.borrow().lifetime) + } }) } @@ -134,31 +148,42 @@ fn idx_push(vec: &mut Vec , val: T) -> u32 { } /// Resolve a syntax object to a name, per MTWT. -pub fn resolve(id: Ident) -> Name { - with_sctable(|sctable| { - with_resolve_table_mut(|resolve_table| { +pub fn resolve(id: Ident, ns: IdentKind) -> Name { + with_sctable(ns, |sctable| { + with_resolve_table_mut(ns, |resolve_table| { resolve_internal(id, sctable, resolve_table) }) }) } type ResolveTable = HashMap<(Name,SyntaxContext),Name>; +struct ResolveTables { + plain: RefCell, + lifetime: RefCell, +} // okay, I admit, putting this in TLS is not so nice: // fetch the SCTable from TLS, create one if it doesn't yet exist. -fn with_resolve_table_mut(op: |&mut ResolveTable| -> T) -> T { - local_data_key!(resolve_table_key: Rc>) +fn with_resolve_table_mut(ns: IdentKind, + op: |&mut ResolveTable| -> T) -> T { + local_data_key!(resolve_table_key: Rc) local_data::get(resolve_table_key, |opt_ts| { - let table = match opt_ts { + let tables = match opt_ts { None => { - let ts = Rc::new(RefCell::new(HashMap::new())); + let ts = Rc::new(ResolveTables { + plain: RefCell::new(HashMap::new()), + lifetime: RefCell::new(HashMap::new()), + }); local_data::set(resolve_table_key, ts.clone()); ts } Some(ts) => ts.clone() }; - op(table.borrow().borrow_mut().get()) + match ns { + PlainIdent => op(tables.borrow().plain.borrow_mut().get()), + LifetimeIdent => op(tables.borrow().lifetime.borrow_mut().get()) + } }) } @@ -206,8 +231,8 @@ fn resolve_internal(id: Ident, } /// Compute the marks associated with a syntax context. -pub fn marksof(ctxt: SyntaxContext, stopname: Name) -> Vec { - with_sctable(|table| marksof_internal(ctxt, stopname, table)) +pub fn marksof(ctxt: SyntaxContext, stopname: Name, ns: IdentKind) -> Vec { + with_sctable(ns, |table| marksof_internal(ctxt, stopname, table)) } // the internal function for computing marks @@ -247,8 +272,8 @@ fn marksof_internal(ctxt: SyntaxContext, /// Return the outer mark for a context with a mark at the outside. /// FAILS when outside is not a mark. -pub fn outer_mark(ctxt: SyntaxContext) -> Mrk { - with_sctable(|sctable| { +pub fn outer_mark(ctxt: SyntaxContext, ns: IdentKind) -> Mrk { + with_sctable(ns, |sctable| { match *sctable.table.borrow().get().get(ctxt as uint) { Mark(mrk, _) => mrk, _ => fail!("can't retrieve outer mark when outside is not a mark") @@ -455,7 +480,7 @@ mod tests { #[test] fn mtwt_resolve_test(){ let a = 40; - assert_eq!(resolve(id(a,EMPTY_CTXT)),a); + assert_eq!(resolve(id(a,EMPTY_CTXT), PlainIdent),a); } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index e5b90393e0ad3..3865646f314c4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -246,7 +246,7 @@ pub trait Folder { }) } - fn fold_ident(&mut self, i: Ident) -> Ident { + fn fold_ident(&mut self, i: Ident, _: IdentKind) -> Ident { i } @@ -255,7 +255,7 @@ pub trait Folder { span: self.new_span(p.span), global: p.global, segments: p.segments.map(|segment| ast::PathSegment { - identifier: self.fold_ident(segment.identifier), + identifier: self.fold_ident(segment.identifier, PlainIdent), lifetimes: segment.lifetimes.map(|l| fold_lifetime(l, self)), types: segment.types.map(|&typ| self.fold_ty(typ)), }) @@ -384,7 +384,7 @@ pub fn fold_tts(tts: &[TokenTree], fld: &mut T) -> Vec { sep.as_ref().map(|tok|maybe_fold_ident(tok,fld)), is_optional), TTNonterminal(sp,ref ident) => - TTNonterminal(sp,fld.fold_ident(*ident)) + TTNonterminal(sp,fld.fold_ident(*ident, PlainIdent)) } }).collect() } @@ -393,9 +393,9 @@ pub fn fold_tts(tts: &[TokenTree], fld: &mut T) -> Vec { fn maybe_fold_ident(t: &token::Token, fld: &mut T) -> token::Token { match *t { token::IDENT(id, followed_by_colons) => { - token::IDENT(fld.fold_ident(id), followed_by_colons) + token::IDENT(fld.fold_ident(id, PlainIdent), followed_by_colons) } - token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id)), + token::LIFETIME(id) => token::LIFETIME(fld.fold_ident(id, LifetimeIdent)), _ => (*t).clone() } } @@ -482,7 +482,7 @@ fn fold_struct_field(f: &StructField, fld: &mut T) -> StructField { fn fold_field_(field: Field, folder: &mut T) -> Field { ast::Field { - ident: respan(field.ident.span, folder.fold_ident(field.ident.node)), + ident: respan(field.ident.span, folder.fold_ident(field.ident.node, PlainIdent)), expr: folder.fold_expr(field.expr), span: folder.new_span(field.span), } @@ -601,7 +601,7 @@ pub fn noop_fold_item_underscore(i: &Item_, folder: &mut T) -> Item_ pub fn noop_fold_type_method(m: &TypeMethod, fld: &mut T) -> TypeMethod { TypeMethod { id: fld.new_id(m.id), // Needs to be first, for ast_map. - ident: fld.fold_ident(m.ident), + ident: fld.fold_ident(m.ident, PlainIdent), attrs: m.attrs.map(|a| fold_attribute_(*a, fld)), purity: m.purity, decl: fld.fold_fn_decl(m.decl), @@ -642,7 +642,7 @@ pub fn noop_fold_item(i: &Item, folder: &mut T) -> SmallVector<@Item> SmallVector::one(@Item { id: id, - ident: folder.fold_ident(ident), + ident: folder.fold_ident(ident, PlainIdent), attrs: i.attrs.map(|e| fold_attribute_(*e, folder)), node: node, vis: i.vis, @@ -653,7 +653,7 @@ pub fn noop_fold_item(i: &Item, folder: &mut T) -> SmallVector<@Item> pub fn noop_fold_foreign_item(ni: &ForeignItem, folder: &mut T) -> @ForeignItem { @ForeignItem { id: folder.new_id(ni.id), // Needs to be first, for ast_map. - ident: folder.fold_ident(ni.ident), + ident: folder.fold_ident(ni.ident, PlainIdent), attrs: ni.attrs.map(|x| fold_attribute_(*x, folder)), node: match ni.node { ForeignItemFn(ref fdec, ref generics) => { @@ -676,7 +676,7 @@ pub fn noop_fold_foreign_item(ni: &ForeignItem, folder: &mut T) -> @F pub fn noop_fold_method(m: &Method, folder: &mut T) -> @Method { @Method { id: folder.new_id(m.id), // Needs to be first, for ast_map. - ident: folder.fold_ident(m.ident), + ident: folder.fold_ident(m.ident, PlainIdent), attrs: m.attrs.map(|a| fold_attribute_(*a, folder)), generics: fold_generics(&m.generics, folder), explicit_self: folder.fold_explicit_self(&m.explicit_self), @@ -753,7 +753,7 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { } ExprMethodCall(i, ref tps, ref args) => { ExprMethodCall( - folder.fold_ident(i), + folder.fold_ident(i, PlainIdent), tps.map(|&x| folder.fold_ty(x)), args.map(|&x| folder.fold_expr(x))) } @@ -782,11 +782,11 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { ExprForLoop(folder.fold_pat(pat), folder.fold_expr(iter), folder.fold_block(body), - maybe_ident.map(|i| folder.fold_ident(i))) + maybe_ident.map(|i| folder.fold_ident(i, LifetimeIdent))) } ExprLoop(body, opt_ident) => { ExprLoop(folder.fold_block(body), - opt_ident.map(|x| folder.fold_ident(x))) + opt_ident.map(|x| folder.fold_ident(x, LifetimeIdent))) } ExprMatch(expr, ref arms) => { ExprMatch(folder.fold_expr(expr), @@ -809,7 +809,7 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { } ExprField(el, id, ref tys) => { ExprField(folder.fold_expr(el), - folder.fold_ident(id), + folder.fold_ident(id, PlainIdent), tys.map(|&x| folder.fold_ty(x))) } ExprIndex(el, er) => { @@ -817,8 +817,10 @@ pub fn noop_fold_expr(e: @Expr, folder: &mut T) -> @Expr { } ExprPath(ref pth) => ExprPath(folder.fold_path(pth)), ExprLogLevel => ExprLogLevel, - ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|x| folder.fold_ident(x))), - ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|x| folder.fold_ident(x))), + ExprBreak(opt_ident) => + ExprBreak(opt_ident.map(|x| folder.fold_ident(x, LifetimeIdent))), + ExprAgain(opt_ident) => + ExprAgain(opt_ident.map(|x| folder.fold_ident(x, LifetimeIdent))), ExprRet(ref e) => { ExprRet(e.map(|x| folder.fold_expr(x))) } @@ -890,7 +892,7 @@ mod test { struct ToZzIdentFolder; impl Folder for ToZzIdentFolder { - fn fold_ident(&mut self, _: ast::Ident) -> ast::Ident { + fn fold_ident(&mut self, _: ast::Ident, _: ast::IdentKind) -> ast::Ident { token::str_to_ident("zz") } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 71ee32b4aade7..52d639de6a969 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -722,8 +722,10 @@ pub fn is_reserved_keyword(tok: &Token) -> bool { pub fn mtwt_token_eq(t1 : &Token, t2 : &Token) -> bool { match (t1,t2) { - (&IDENT(id1,_),&IDENT(id2,_)) | (&LIFETIME(id1),&LIFETIME(id2)) => - mtwt::resolve(id1) == mtwt::resolve(id2), + (&IDENT(id1,_),&IDENT(id2,_)) => + mtwt::resolve(id1, ast::PlainIdent) == mtwt::resolve(id2, ast::PlainIdent), + (&LIFETIME(id1),&LIFETIME(id2)) => + mtwt::resolve(id1, ast::LifetimeIdent) == mtwt::resolve(id2, ast::LifetimeIdent), _ => *t1 == *t2 } } @@ -736,7 +738,7 @@ mod test { use ext::mtwt; fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident { - ast::Ident{name:id.name,ctxt:mtwt::new_mark(m,id.ctxt)} + ast::Ident{name:id.name,ctxt:mtwt::new_mark(m,id.ctxt,ast::PlainIdent)} } #[test] fn mtwt_token_eq_test() { diff --git a/src/test/run-pass/issue-12512.rs b/src/test/run-pass/issue-12512.rs new file mode 100644 index 0000000000000..e5ab6c39a99df --- /dev/null +++ b/src/test/run-pass/issue-12512.rs @@ -0,0 +1,20 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that variables and loop labels with the same name don't +// shadow each other. + +pub fn main() { + let mut foo = 0i; + 'foo: for _ in range(0, 1) { + foo += 1; + assert_eq!(foo, 1); + } +} diff --git a/src/test/run-pass/loop-labels.rs b/src/test/run-pass/loop-labels.rs new file mode 100644 index 0000000000000..1fd0374967092 --- /dev/null +++ b/src/test/run-pass/loop-labels.rs @@ -0,0 +1,39 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that variables and loop labels with the same name don't +// shadow each other. + +// Tests that loop labels honor their lexical scopes and don't clash with +// each other. + +#[allow(unreachable_code)]; + +pub fn main() { + let mut outer = 0i; + 'bar: loop { + let mut bar = 0i; + 'bar: for _ in range(0, 1) { + bar += 1; + // This should refer to the inner loop + continue 'bar; + unreachable!(); + } + assert_eq!(bar, 1); + outer += 1; + // This should break out of the outer loop + break 'bar; + + 'bar: loop { + unreachable!(); + } + } + assert_eq!(outer, 1); +}