]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #9026 : jbclements/rust/let-var-hygiene, r=jbclements
authorbors <bors@rust-lang.org>
Sat, 7 Sep 2013 06:35:57 +0000 (23:35 -0700)
committerbors <bors@rust-lang.org>
Sat, 7 Sep 2013 06:35:57 +0000 (23:35 -0700)
This is a rebase of my approved pull request from ... the end of June? It introduces hygiene for let-bound variables.

38 files changed:
src/libextra/crypto/sha2.rs
src/librustc/middle/borrowck/mod.rs
src/librustc/middle/entry.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/moves.rs
src/librustc/middle/privacy.rs
src/librustc/middle/resolve.rs
src/librustc/middle/trans/_match.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/trans/context.rs
src/librustc/middle/trans/debuginfo.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/meth.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/_match.rs
src/librustc/middle/typeck/check/method.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/collect.rs
src/libstd/to_bytes.rs
src/libsyntax/ast.rs
src/libsyntax/ast_util.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/quote.rs
src/libsyntax/ext/tt/macro_parser.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/util/interner.rs
src/libsyntax/util/parser_testing.rs
src/test/bench/core-std.rs
src/test/run-pass/hygiene-dodging-1.rs [new file with mode: 0644]
src/test/run-pass/let-var-hygiene.rs [new file with mode: 0644]
src/test/run-pass/syntax-extension-minor.rs

index 96f3e13eb2202530edf5125c5b4ce336a3aae44d..49bbddca1dbb773d648807b5f2a9b846d9be7449 100644 (file)
     add_bytes_to_bits_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
 use digest::Digest;
 
-
-// Sha-512 and Sha-256 use basically the same calculations which are implemented by these macros.
-// Inlining the calculations seems to result in better generated code.
-macro_rules! schedule_round( ($t:expr) => (
-        W[$t] = sigma1(W[$t - 2]) + W[$t - 7] + sigma0(W[$t - 15]) + W[$t - 16];
-    )
-)
-
-macro_rules! sha2_round(
-    ($A:ident, $B:ident, $C:ident, $D:ident,
-     $E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => (
-        {
-            $H += sum1($E) + ch($E, $F, $G) + $K[$t] + W[$t];
-            $D += $H;
-            $H += sum0($A) + maj($A, $B, $C);
-        }
-    )
-)
-
-
-// A structure that represents that state of a digest computation for the SHA-2 512 family of digest
-// functions
+// A structure that represents that state of a digest computation for the SHA-2 512 family
+// of digest functions
 struct Engine512State {
     H0: u64,
     H1: u64,
@@ -108,6 +88,25 @@ fn sigma1(x: u64) -> u64 {
 
         let mut W = [0u64, ..80];
 
+        // Sha-512 and Sha-256 use basically the same calculations which are implemented by
+        // these macros. Inlining the calculations seems to result in better generated code.
+        macro_rules! schedule_round( ($t:expr) => (
+                W[$t] = sigma1(W[$t - 2]) + W[$t - 7] + sigma0(W[$t - 15]) + W[$t - 16];
+                )
+        )
+
+        macro_rules! sha2_round(
+            ($A:ident, $B:ident, $C:ident, $D:ident,
+             $E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => (
+                {
+                    $H += sum1($E) + ch($E, $F, $G) + $K[$t] + W[$t];
+                    $D += $H;
+                    $H += sum0($A) + maj($A, $B, $C);
+                }
+             )
+        )
+
+
         read_u64v_be(W.mut_slice(0, 16), data);
 
         // Putting the message schedule inside the same loop as the round calculations allows for
@@ -505,6 +504,25 @@ fn sigma1(x: u32) -> u32 {
 
         let mut W = [0u32, ..64];
 
+        // Sha-512 and Sha-256 use basically the same calculations which are implemented
+        // by these macros. Inlining the calculations seems to result in better generated code.
+        macro_rules! schedule_round( ($t:expr) => (
+                W[$t] = sigma1(W[$t - 2]) + W[$t - 7] + sigma0(W[$t - 15]) + W[$t - 16];
+                )
+        )
+
+        macro_rules! sha2_round(
+            ($A:ident, $B:ident, $C:ident, $D:ident,
+             $E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => (
+                {
+                    $H += sum1($E) + ch($E, $F, $G) + $K[$t] + W[$t];
+                    $D += $H;
+                    $H += sum0($A) + maj($A, $B, $C);
+                }
+             )
+        )
+
+
         read_u32v_be(W.mut_slice(0, 16), data);
 
         // Putting the message schedule inside the same loop as the round calculations allows for
index 986b3956410bccfa65bf6733712d1c14691e136f..cdae2f5e066c1f3c1eab4cbd64c8a32862532997 100644 (file)
@@ -788,7 +788,7 @@ pub fn append_loan_path_to_str(&self,
                 match fname {
                     mc::NamedField(ref fname) => {
                         out.push_char('.');
-                        out.push_str(token::ident_to_str(fname));
+                        out.push_str(token::interner_get(*fname));
                     }
                     mc::PositionalField(idx) => {
                         out.push_char('#'); // invent a notation here
index 8aa4584e0427e0354a6898b1c6e4f5069ce4eefe..22e6bc3ac2febee28fa8f296d84e3c607381e535 100644 (file)
@@ -81,7 +81,7 @@ pub fn find_entry_point(session: Session, crate: &Crate, ast_map: ast_map::map)
 fn find_item(item: @item, ctxt: @mut EntryContext, visitor: &mut EntryVisitor) {
     match item.node {
         item_fn(*) => {
-            if item.ident == special_idents::main {
+            if item.ident.name == special_idents::main.name {
                 match ctxt.ast_map.find(&item.id) {
                     Some(&ast_map::node_item(_, path)) => {
                         if path.len() == 0 {
index 0171712c0823a042e39e0200595d84f87a6edecf..0f5dd8cda7a99f180bb35312b31f18920d0e899c 100644 (file)
@@ -56,6 +56,7 @@
 use syntax::ast;
 use syntax::codemap::Span;
 use syntax::print::pprust;
+use syntax::parse::token;
 
 #[deriving(Eq)]
 pub enum categorization {
@@ -99,7 +100,7 @@ pub enum InteriorKind {
 
 #[deriving(Eq, IterBytes)]
 pub enum FieldName {
-    NamedField(ast::Ident),
+    NamedField(ast::Name),
     PositionalField(uint)
 }
 
@@ -619,7 +620,7 @@ pub fn cat_field<N:ast_node>(&self,
         @cmt_ {
             id: node.id(),
             span: node.span(),
-            cat: cat_interior(base_cmt, InteriorField(NamedField(f_name))),
+            cat: cat_interior(base_cmt, InteriorField(NamedField(f_name.name))),
             mutbl: base_cmt.mutbl.inherit(),
             ty: f_ty
         }
@@ -1224,9 +1225,9 @@ pub fn ptr_sigil(ptr: PointerKind) -> ~str {
 }
 
 impl Repr for InteriorKind {
-    fn repr(&self, tcx: ty::ctxt) -> ~str {
+    fn repr(&self, _tcx: ty::ctxt) -> ~str {
         match *self {
-            InteriorField(NamedField(fld)) => tcx.sess.str_of(fld).to_owned(),
+            InteriorField(NamedField(fld)) => token::interner_get(fld).to_owned(),
             InteriorField(PositionalField(i)) => fmt!("#%?", i),
             InteriorElement(_) => ~"[]",
         }
index cb672947774a5b9e6216507053fd524b0e56d17a..55783e3568ea6b42854380f0cdf2e78672be7e42 100644 (file)
@@ -429,7 +429,7 @@ pub fn use_expr(&self,
                     // specified and (2) have a type that
                     // moves-by-default:
                     let consume_with = with_fields.iter().any(|tf| {
-                        !fields.iter().any(|f| f.ident == tf.ident) &&
+                        !fields.iter().any(|f| f.ident.name == tf.ident.name) &&
                             ty::type_moves_by_default(self.tcx, tf.mt.ty)
                     });
 
index 04fceb3e8e3cd87eb622aa7a4a6cb9ae0e4554dc..d6f61c6328a0bbf883506b948b3b1d624742b0eb 100644 (file)
@@ -206,7 +206,7 @@ fn local_item_is_private(&mut self, span: Span, item_id: NodeId) -> bool {
     fn check_field(&mut self, span: Span, id: ast::DefId, ident: ast::Ident) {
         let fields = ty::lookup_struct_fields(self.tcx, id);
         for field in fields.iter() {
-            if field.ident != ident { loop; }
+            if field.ident.name != ident.name { loop; }
             if field.vis == private {
                 self.tcx.sess.span_err(span, fmt!("field `%s` is private",
                                              token::ident_to_str(&ident)));
index 09491bd28be305584ac6d4e6c396b71608e0999b..292047d885d5245fd99717ae97f454e04453bce0 100644 (file)
 
 use syntax::ast::*;
 use syntax::ast;
-use syntax::ast_util::{def_id_of_def, local_def};
+use syntax::ast_util::{def_id_of_def, local_def, mtwt_resolve};
 use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method};
 use syntax::ast_util::{Privacy, Public, Private};
 use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy};
 use syntax::attr;
 use syntax::parse::token;
-use syntax::parse::token::ident_interner;
+use syntax::parse::token::{ident_interner, interner_get};
 use syntax::parse::token::special_idents;
 use syntax::print::pprust::path_to_str;
 use syntax::codemap::{Span, dummy_sp, BytePos};
@@ -51,7 +51,7 @@ pub struct binding_info {
 }
 
 // Map from the name in a pattern to its binding mode.
-pub type BindingMap = HashMap<Ident,binding_info>;
+pub type BindingMap = HashMap<Name,binding_info>;
 
 // Trait method resolution
 pub type TraitMap = HashMap<NodeId,@mut ~[DefId]>;
@@ -311,7 +311,7 @@ pub enum DuplicateCheckingMode {
 
 /// One local scope.
 pub struct Rib {
-    bindings: @mut HashMap<Ident, DefLike>,
+    bindings: @mut HashMap<Name, DefLike>,
     self_binding: @mut Option<DefLike>,
     kind: RibKind,
 }
@@ -445,12 +445,12 @@ pub struct Module {
     def_id: Option<DefId>,
     kind: ModuleKind,
 
-    children: @mut HashMap<Ident, @mut NameBindings>,
+    children: @mut HashMap<Name, @mut NameBindings>,
     imports: @mut ~[@ImportDirective],
 
     // The external module children of this node that were declared with
     // `extern mod`.
-    external_module_children: @mut HashMap<Ident, @mut Module>,
+    external_module_children: @mut HashMap<Name, @mut Module>,
 
     // The anonymous children of this node. Anonymous children are pseudo-
     // modules that are implicitly created around items contained within
@@ -469,7 +469,7 @@ pub struct Module {
     anonymous_children: @mut HashMap<NodeId,@mut Module>,
 
     // The status of resolving each import in this module.
-    import_resolutions: @mut HashMap<Ident, @mut ImportResolution>,
+    import_resolutions: @mut HashMap<Name, @mut ImportResolution>,
 
     // The number of unresolved globs that this module exports.
     glob_count: uint,
@@ -759,15 +759,14 @@ pub fn NameBindings() -> NameBindings {
 
 /// Interns the names of the primitive types.
 pub struct PrimitiveTypeTable {
-    primitive_types: HashMap<Ident,prim_ty>,
+    primitive_types: HashMap<Name,prim_ty>,
 }
 
 impl PrimitiveTypeTable {
     pub fn intern(&mut self,
                   string: &str,
                   primitive_type: prim_ty) {
-        let ident = token::str_to_ident(string);
-        self.primitive_types.insert(ident, primitive_type);
+        self.primitive_types.insert(token::intern(string), primitive_type);
     }
 }
 
@@ -873,7 +872,7 @@ pub struct Resolver {
 
     graph_root: @mut NameBindings,
 
-    method_map: @mut HashMap<Ident, HashSet<DefId>>,
+    method_map: @mut HashMap<Name, HashSet<DefId>>,
     structs: HashSet<DefId>,
 
     // The number of imports that are currently unresolved.
@@ -1036,10 +1035,10 @@ pub fn add_child(@mut self,
 
         // Add or reuse the child.
         let new_parent = ModuleReducedGraphParent(module_);
-        match module_.children.find(&name) {
+        match module_.children.find(&name.name) {
             None => {
                 let child = @mut NameBindings();
-                module_.children.insert(name, child);
+                module_.children.insert(name.name, child);
                 return (child, new_parent);
             }
             Some(&child) => {
@@ -1307,7 +1306,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                     } if path.segments.len() == 1 => {
                         let name = path_to_ident(path);
 
-                        let new_parent = match parent.children.find(&name) {
+                        let new_parent = match parent.children.find(&name.name) {
                             // It already exists
                             Some(&child) if child.get_module_if_available()
                                                  .is_some() &&
@@ -1426,7 +1425,7 @@ pub fn build_reduced_graph_for_item(@mut self,
                     match ty_m.explicit_self.node {
                         sty_static => {}
                         _ => {
-                            method_names.insert(ident, ());
+                            method_names.insert(ident.name, ());
                         }
                     }
                 }
@@ -1582,7 +1581,7 @@ pub fn build_reduced_graph_for_view_item(@mut self,
                                                           false);
 
                         parent.external_module_children.insert(
-                            name,
+                            name.name,
                             external_module);
 
                         self.build_reduced_graph_for_external_crate(
@@ -1727,7 +1726,7 @@ trait method '%s'",
 
                   // Add it to the trait info if not static.
                   if explicit_self != sty_static {
-                      interned_method_names.insert(method_name);
+                      interned_method_names.insert(method_name.name);
                   }
               }
               for name in interned_method_names.iter() {
@@ -1981,7 +1980,7 @@ pub fn build_import_directive(@mut self,
                        self.idents_to_str(directive.module_path),
                        self.session.str_of(target));
 
-                match module_.import_resolutions.find(&target) {
+                match module_.import_resolutions.find(&target.name) {
                     Some(&resolution) => {
                         debug!("(building import directive) bumping \
                                 reference");
@@ -1996,7 +1995,7 @@ pub fn build_import_directive(@mut self,
                         debug!("(building import directive) creating new");
                         let resolution = @mut ImportResolution::new(privacy, id);
                         resolution.outstanding_references = 1;
-                        module_.import_resolutions.insert(target, resolution);
+                        module_.import_resolutions.insert(target.name, resolution);
                     }
                 }
             }
@@ -2281,7 +2280,7 @@ pub fn resolve_single_import(@mut self,
 
         // Search for direct children of the containing module.
         self.populate_module_if_necessary(containing_module);
-        match containing_module.children.find(&source) {
+        match containing_module.children.find(&source.name) {
             None => {
                 // Continue.
             }
@@ -2315,7 +2314,7 @@ pub fn resolve_single_import(@mut self,
                 // Now search the exported imports within the containing
                 // module.
 
-                match containing_module.import_resolutions.find(&source) {
+                match containing_module.import_resolutions.find(&source.name) {
                     None => {
                         // The containing module definitely doesn't have an
                         // exported import with the name in question. We can
@@ -2386,7 +2385,7 @@ fn get_binding(this: @mut Resolver,
             BoundResult(*) => {}
             _ => {
                 match containing_module.external_module_children
-                                       .find(&source) {
+                                       .find(&source.name) {
                     None => {} // Continue.
                     Some(module) => {
                         let name_bindings =
@@ -2400,8 +2399,8 @@ fn get_binding(this: @mut Resolver,
         }
 
         // We've successfully resolved the import. Write the results in.
-        assert!(module_.import_resolutions.contains_key(&target));
-        let import_resolution = module_.import_resolutions.get(&target);
+        assert!(module_.import_resolutions.contains_key(&target.name));
+        let import_resolution = module_.import_resolutions.get(&target.name);
 
         match value_result {
             BoundResult(target_module, name_bindings) => {
@@ -2563,15 +2562,15 @@ pub fn resolve_glob_import(@mut self,
             }
         }
 
-        let merge_import_resolution = |ident,
+        let merge_import_resolution = |name,
                                        name_bindings: @mut NameBindings| {
             let dest_import_resolution;
-            match module_.import_resolutions.find(&ident) {
+            match module_.import_resolutions.find(&name) {
                 None => {
                     // Create a new import resolution from this child.
                     dest_import_resolution = @mut ImportResolution::new(privacy, id);
                     module_.import_resolutions.insert
-                        (ident, dest_import_resolution);
+                        (name, dest_import_resolution);
                 }
                 Some(&existing_import_resolution) => {
                     dest_import_resolution = existing_import_resolution;
@@ -2580,7 +2579,7 @@ pub fn resolve_glob_import(@mut self,
 
             debug!("(resolving glob import) writing resolution `%s` in `%s` \
                     to `%s`, privacy=%?",
-                   self.session.str_of(ident),
+                   interner_get(name),
                    self.module_to_str(containing_module),
                    self.module_to_str(module_),
                    dest_import_resolution.privacy);
@@ -2602,15 +2601,15 @@ pub fn resolve_glob_import(@mut self,
 
         // Add all children from the containing module.
         self.populate_module_if_necessary(containing_module);
-        for (&ident, name_bindings) in containing_module.children.iter() {
-            merge_import_resolution(ident, *name_bindings);
+        for (&name, name_bindings) in containing_module.children.iter() {
+            merge_import_resolution(name, *name_bindings);
         }
 
         // Add external module children from the containing module.
-        for (&ident, module) in containing_module.external_module_children.iter() {
+        for (&name, module) in containing_module.external_module_children.iter() {
             let name_bindings =
                 @mut Resolver::create_name_bindings_from_module(*module);
-            merge_import_resolution(ident, name_bindings);
+            merge_import_resolution(name, name_bindings);
         }
 
         debug!("(resolving glob import) successfully resolved import");
@@ -2836,7 +2835,7 @@ pub fn resolve_item_in_lexical_scope(@mut self,
         // The current module node is handled specially. First, check for
         // its immediate children.
         self.populate_module_if_necessary(module_);
-        match module_.children.find(&name) {
+        match module_.children.find(&name.name) {
             Some(name_bindings)
                     if name_bindings.defined_in_namespace(namespace) => {
                 return Success(Target::new(module_, *name_bindings));
@@ -2848,7 +2847,7 @@ pub fn resolve_item_in_lexical_scope(@mut self,
         // all its imports in the usual way; this is because chains of
         // adjacent import statements are processed as though they mutated the
         // current scope.
-        match module_.import_resolutions.find(&name) {
+        match module_.import_resolutions.find(&name.name) {
             None => {
                 // Not found; continue.
             }
@@ -2872,7 +2871,7 @@ pub fn resolve_item_in_lexical_scope(@mut self,
 
         // Search for external modules.
         if namespace == TypeNS {
-            match module_.external_module_children.find(&name) {
+            match module_.external_module_children.find(&name.name) {
                 None => {}
                 Some(module) => {
                     let name_bindings =
@@ -3034,8 +3033,9 @@ pub fn get_nearest_normal_module_parent_or_self(@mut self,
         }
     }
 
-    /// Resolves a "module prefix". A module prefix is one of (a) `self::`;
+    /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`;
     /// (b) some chain of `super::`.
+    /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) *
     pub fn resolve_module_prefix(@mut self,
                                  module_: @mut Module,
                                  module_path: &[Ident])
@@ -3091,7 +3091,7 @@ pub fn resolve_name_in_module(@mut self,
 
         // First, check the direct children of the module.
         self.populate_module_if_necessary(module_);
-        match module_.children.find(&name) {
+        match module_.children.find(&name.name) {
             Some(name_bindings)
                     if name_bindings.defined_in_namespace(namespace) => {
                 debug!("(resolving name in module) found node as child");
@@ -3112,7 +3112,7 @@ pub fn resolve_name_in_module(@mut self,
         }
 
         // Check the list of resolved imports.
-        match module_.import_resolutions.find(&name) {
+        match module_.import_resolutions.find(&name.name) {
             Some(import_resolution) => {
                 if import_resolution.privacy == Public &&
                         import_resolution.outstanding_references != 0 {
@@ -3147,7 +3147,7 @@ pub fn resolve_name_in_module(@mut self,
 
         // Finally, search through external children.
         if namespace == TypeNS {
-            match module_.external_module_children.find(&name) {
+            match module_.external_module_children.find(&name.name) {
                 None => {}
                 Some(module) => {
                     let name_bindings =
@@ -3273,7 +3273,7 @@ pub fn record_exports_for_module(@mut self, module_: @mut Module) {
 
     pub fn add_exports_of_namebindings(@mut self,
                                        exports2: &mut ~[Export2],
-                                       ident: Ident,
+                                       name: Name,
                                        namebindings: @mut NameBindings,
                                        ns: Namespace,
                                        reexport: bool) {
@@ -3282,11 +3282,11 @@ pub fn add_exports_of_namebindings(@mut self,
             (Some(d), Some(Public)) => {
                 debug!("(computing exports) YES: %s '%s' => %?",
                        if reexport { ~"reexport" } else { ~"export"},
-                       self.session.str_of(ident),
+                       interner_get(name),
                        def_id_of_def(d));
                 exports2.push(Export2 {
                     reexport: reexport,
-                    name: self.session.str_of(ident),
+                    name: interner_get(name),
                     def_id: def_id_of_def(d)
                 });
             }
@@ -3302,10 +3302,10 @@ pub fn add_exports_of_namebindings(@mut self,
     pub fn add_exports_for_module(@mut self,
                                   exports2: &mut ~[Export2],
                                   module_: @mut Module) {
-        for (ident, importresolution) in module_.import_resolutions.iter() {
+        for (name, importresolution) in module_.import_resolutions.iter() {
             if importresolution.privacy != Public {
                 debug!("(computing exports) not reexporting private `%s`",
-                       self.session.str_of(*ident));
+                       interner_get(*name));
                 loop;
             }
             let xs = [TypeNS, ValueNS];
@@ -3313,9 +3313,9 @@ pub fn add_exports_for_module(@mut self,
                 match importresolution.target_for_namespace(*ns) {
                     Some(target) => {
                         debug!("(computing exports) maybe reexport '%s'",
-                               self.session.str_of(*ident));
+                               interner_get(*name));
                         self.add_exports_of_namebindings(&mut *exports2,
-                                                         *ident,
+                                                         *name,
                                                          target.bindings,
                                                          *ns,
                                                          true)
@@ -3354,7 +3354,7 @@ pub fn with_scope(@mut self, name: Option<Ident>, f: &fn()) {
             }
             Some(name) => {
                 self.populate_module_if_necessary(orig_module);
-                match orig_module.children.find(&name) {
+                match orig_module.children.find(&name.name) {
                     None => {
                         debug!("!!! (with scope) didn't find `%s` in `%s`",
                                self.session.str_of(name),
@@ -3498,7 +3498,7 @@ pub fn upvarify(@mut self,
 
     pub fn search_ribs(@mut self,
                        ribs: &mut ~[@Rib],
-                       name: Ident,
+                       name: Name,
                        span: Span,
                        allow_capturing_self: AllowCapturingSelfFlag)
                        -> Option<DefLike> {
@@ -3591,7 +3591,9 @@ pub fn resolve_item(@mut self, item: @item, visitor: &mut ResolveVisitor) {
                 // Create a new rib for the self type.
                 let self_type_rib = @Rib::new(NormalRibKind);
                 self.type_ribs.push(self_type_rib);
-                self_type_rib.bindings.insert(self.type_self_ident,
+                // plain insert (no renaming)
+                let name = self.type_self_ident.name;
+                self_type_rib.bindings.insert(name,
                                               DlDef(DefSelfTy(item.id)));
 
                 // Create a new rib for the trait-wide type parameters.
@@ -3723,7 +3725,7 @@ pub fn with_type_parameter_rib(@mut self,
                 self.type_ribs.push(function_type_rib);
 
                 for (index, type_parameter) in generics.ty_params.iter().enumerate() {
-                    let name = type_parameter.ident;
+                    let ident = type_parameter.ident;
                     debug!("with_type_parameter_rib: %d %d", node_id,
                            type_parameter.id);
                     let def_like = DlDef(DefTyParam
@@ -3733,7 +3735,8 @@ pub fn with_type_parameter_rib(@mut self,
                     // the item that bound it
                     self.record_def(type_parameter.id,
                                     DefTyParamBinder(node_id));
-                    function_type_rib.bindings.insert(name, def_like);
+                    // plain insert (no renaming)
+                    function_type_rib.bindings.insert(ident.name, def_like);
                 }
             }
 
@@ -4064,17 +4067,23 @@ pub fn resolve_local(@mut self, local: @Local, visitor: &mut ResolveVisitor) {
                              None, visitor);
     }
 
+    // build a map from pattern identifiers to binding-info's.
+    // this is done hygienically. This could arise for a macro
+    // that expands into an or-pattern where one 'x' was from the
+    // user and one 'x' came from the macro.
     pub fn binding_mode_map(@mut self, pat: @Pat) -> BindingMap {
         let mut result = HashMap::new();
         do pat_bindings(self.def_map, pat) |binding_mode, _id, sp, path| {
-            let ident = path_to_ident(path);
-            result.insert(ident,
+            let name = mtwt_resolve(path_to_ident(path));
+            result.insert(name,
                           binding_info {span: sp,
                                         binding_mode: binding_mode});
         }
         return result;
     }
 
+    // check that all of the arms in an or-pattern have exactly the
+    // same set of bindings, with the same binding modes for each.
     pub fn check_consistent_bindings(@mut self, arm: &Arm) {
         if arm.pats.len() == 0 { return; }
         let map_0 = self.binding_mode_map(arm.pats[0]);
@@ -4088,7 +4097,7 @@ pub fn check_consistent_bindings(@mut self, arm: &Arm) {
                         p.span,
                         fmt!("variable `%s` from pattern #1 is \
                                   not bound in pattern #%u",
-                             self.session.str_of(key), i + 1));
+                             interner_get(key), i + 1));
                   }
                   Some(binding_i) => {
                     if binding_0.binding_mode != binding_i.binding_mode {
@@ -4096,7 +4105,7 @@ pub fn check_consistent_bindings(@mut self, arm: &Arm) {
                             binding_i.span,
                             fmt!("variable `%s` is bound with different \
                                       mode in pattern #%u than in pattern #1",
-                                 self.session.str_of(key), i + 1));
+                                 interner_get(key), i + 1));
                     }
                   }
                 }
@@ -4108,7 +4117,7 @@ pub fn check_consistent_bindings(@mut self, arm: &Arm) {
                         binding.span,
                         fmt!("variable `%s` from pattern #%u is \
                                   not bound in pattern #1",
-                             self.session.str_of(key), i + 1));
+                             interner_get(key), i + 1));
                 }
             }
         }
@@ -4170,11 +4179,11 @@ pub fn resolve_type(@mut self, ty: &Ty, visitor: &mut ResolveVisitor) {
 
                 // First, check to see whether the name is a primitive type.
                 if path.segments.len() == 1 {
-                    let name = path.segments.last().identifier;
+                    let id = path.segments.last().identifier;
 
                     match self.primitive_type_table
                             .primitive_types
-                            .find(&name) {
+                            .find(&id.name) {
 
                         Some(&primitive_type) => {
                             result_def =
@@ -4272,7 +4281,7 @@ pub fn resolve_pattern(@mut self,
                            mutability: Mutability,
                            // Maps idents to the node ID for the (outermost)
                            // pattern that binds them
-                           bindings_list: Option<@mut HashMap<Ident,NodeId>>,
+                           bindings_list: Option<@mut HashMap<Name,NodeId>>,
                            visitor: &mut ResolveVisitor) {
         let pat_id = pattern.id;
         do walk_pat(pattern) |pattern| {
@@ -4290,13 +4299,14 @@ pub fn resolve_pattern(@mut self,
                     // what you want).
 
                     let ident = path.segments[0].identifier;
+                    let renamed = mtwt_resolve(ident);
 
                     match self.resolve_bare_identifier_pattern(ident) {
                         FoundStructOrEnumVariant(def)
                                 if mode == RefutableMode => {
                             debug!("(resolving pattern) resolving `%s` to \
                                     struct or enum variant",
-                                    self.session.str_of(ident));
+                                   interner_get(renamed));
 
                             self.enforce_default_binding_mode(
                                 pattern,
@@ -4310,13 +4320,12 @@ struct or enum variant",
                                                         shadows an enum \
                                                         variant or unit-like \
                                                         struct in scope",
-                                                        self.session
-                                                            .str_of(ident)));
+                                                       interner_get(renamed)));
                         }
                         FoundConst(def) if mode == RefutableMode => {
                             debug!("(resolving pattern) resolving `%s` to \
                                     constant",
-                                    self.session.str_of(ident));
+                                   interner_get(renamed));
 
                             self.enforce_default_binding_mode(
                                 pattern,
@@ -4331,7 +4340,7 @@ struct in scope",
                         }
                         BareIdentifierPatternUnresolved => {
                             debug!("(resolving pattern) binding `%s`",
-                                   self.session.str_of(ident));
+                                   interner_get(renamed));
 
                             let is_mutable = mutability == Mutable;
 
@@ -4366,16 +4375,16 @@ struct in scope",
 
                             match bindings_list {
                                 Some(bindings_list)
-                                if !bindings_list.contains_key(&ident) => {
+                                if !bindings_list.contains_key(&renamed) => {
                                     let this = &mut *self;
                                     let last_rib = this.value_ribs[
                                             this.value_ribs.len() - 1];
-                                    last_rib.bindings.insert(ident,
+                                    last_rib.bindings.insert(renamed,
                                                              DlDef(def));
-                                    bindings_list.insert(ident, pat_id);
+                                    bindings_list.insert(renamed, pat_id);
                                 }
                                 Some(b) => {
-                                  if b.find(&ident) == Some(&pat_id) {
+                                  if b.find(&renamed) == Some(&pat_id) {
                                       // Then this is a duplicate variable
                                       // in the same disjunct, which is an
                                       // error
@@ -4391,7 +4400,7 @@ struct in scope",
                                     let this = &mut *self;
                                     let last_rib = this.value_ribs[
                                             this.value_ribs.len() - 1];
-                                    last_rib.bindings.insert(ident,
+                                    last_rib.bindings.insert(renamed,
                                                              DlDef(def));
                                 }
                             }
@@ -4607,6 +4616,7 @@ pub fn resolve_path(@mut self,
         return unqualified_def;
     }
 
+    // resolve a single identifier (used as a varref)
     pub fn resolve_identifier(@mut self,
                               identifier: Ident,
                               namespace: Namespace,
@@ -4639,7 +4649,7 @@ pub fn resolve_definition_of_name_in_module(@mut self,
                                                 -> NameDefinition {
         // First, search children.
         self.populate_module_if_necessary(containing_module);
-        match containing_module.children.find(&name) {
+        match containing_module.children.find(&name.name) {
             Some(child_name_bindings) => {
                 match (child_name_bindings.def_for_namespace(namespace),
                        child_name_bindings.privacy_for_namespace(namespace)) {
@@ -4662,7 +4672,7 @@ pub fn resolve_definition_of_name_in_module(@mut self,
         }
 
         // Next, search import resolutions.
-        match containing_module.import_resolutions.find(&name) {
+        match containing_module.import_resolutions.find(&name.name) {
             Some(import_resolution) if import_resolution.privacy == Public ||
                                        xray == Xray => {
                 match (*import_resolution).target_for_namespace(namespace) {
@@ -4690,7 +4700,7 @@ pub fn resolve_definition_of_name_in_module(@mut self,
 
         // Finally, search through external children.
         if namespace == TypeNS {
-            match containing_module.external_module_children.find(&name) {
+            match containing_module.external_module_children.find(&name.name) {
                 None => {}
                 Some(module) => {
                     match module.def_id {
@@ -4706,25 +4716,13 @@ pub fn resolve_definition_of_name_in_module(@mut self,
         return NoNameDefinition;
     }
 
-    pub fn intern_module_part_of_path(@mut self, path: &Path) -> ~[Ident] {
-        let mut module_path_idents = ~[];
-        for (index, segment) in path.segments.iter().enumerate() {
-            if index == path.segments.len() - 1 {
-                break;
-            }
-
-            module_path_idents.push(segment.identifier);
-        }
-
-        return module_path_idents;
-    }
-
+    // resolve a "module-relative" path, e.g. a::b::c
     pub fn resolve_module_relative_path(@mut self,
                                         path: &Path,
                                         xray: XrayFlag,
                                         namespace: Namespace)
                                         -> Option<Def> {
-        let module_path_idents = self.intern_module_part_of_path(path);
+        let module_path_idents = path.segments.init().map(|ps| ps.identifier);
 
         let containing_module;
         match self.resolve_module_path(self.current_module,
@@ -4749,9 +4747,9 @@ pub fn resolve_module_relative_path(@mut self,
             }
         }
 
-        let name = path.segments.last().identifier;
+        let ident = path.segments.last().identifier;
         let def = match self.resolve_definition_of_name_in_module(containing_module,
-                                                        name,
+                                                        ident,
                                                         namespace,
                                                         xray) {
             NoNameDefinition => {
@@ -4764,7 +4762,7 @@ pub fn resolve_module_relative_path(@mut self,
         };
         match containing_module.kind {
             TraitModuleKind | ImplModuleKind => {
-                match self.method_map.find(&name) {
+                match self.method_map.find(&ident.name) {
                     Some(s) => {
                         match containing_module.def_id {
                             Some(def_id) if s.contains(&def_id) => {
@@ -4790,7 +4788,7 @@ pub fn resolve_crate_relative_path(@mut self,
                                        xray: XrayFlag,
                                        namespace: Namespace)
                                        -> Option<Def> {
-        let module_path_idents = self.intern_module_part_of_path(path);
+        let module_path_idents = path.segments.init().map(|ps| ps.identifier);
 
         let root_module = self.graph_root.get_module();
 
@@ -4841,12 +4839,14 @@ pub fn resolve_identifier_in_local_ribs(@mut self,
         let search_result;
         match namespace {
             ValueNS => {
-                search_result = self.search_ribs(self.value_ribs, ident,
+                let renamed = mtwt_resolve(ident);
+                search_result = self.search_ribs(self.value_ribs, renamed,
                                                  span,
                                                  DontAllowCapturingSelf);
             }
             TypeNS => {
-                search_result = self.search_ribs(self.type_ribs, ident,
+                let name = ident.name;
+                search_result = self.search_ribs(self.type_ribs, name,
                                                  span, AllowCapturingSelf);
             }
         }
@@ -4957,7 +4957,7 @@ pub fn find_best_match_for_name(@mut self,
         while j != 0 {
             j -= 1;
             for (&k, _) in this.value_ribs[j].bindings.iter() {
-                maybes.push(this.session.str_of(k));
+                maybes.push(interner_get(k));
                 values.push(uint::max_value);
             }
         }
@@ -5146,7 +5146,8 @@ pub fn resolve_expr(@mut self, expr: @Expr, visitor: &mut ResolveVisitor) {
                         let this = &mut *self;
                         let def_like = DlDef(DefLabel(expr.id));
                         let rib = this.label_ribs[this.label_ribs.len() - 1];
-                        rib.bindings.insert(label, def_like);
+                        // plain insert (no renaming)
+                        rib.bindings.insert(label.name, def_like);
                     }
 
                     visit::walk_expr(visitor, expr, ());
@@ -5156,7 +5157,8 @@ pub fn resolve_expr(@mut self, expr: @Expr, visitor: &mut ResolveVisitor) {
             ExprForLoop(*) => fail!("non-desugared expr_for_loop"),
 
             ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
-                match self.search_ribs(self.label_ribs, label, expr.span,
+                let name = label.name;
+                match self.search_ribs(self.label_ribs, name, expr.span,
                                        DontAllowCapturingSelf) {
                     None =>
                         self.resolve_error(expr.span,
@@ -5284,7 +5286,7 @@ pub fn search_for_traits_containing_method(@mut self, name: Ident)
 
         let mut found_traits = ~[];
         let mut search_module = self.current_module;
-        match self.method_map.find(&name) {
+        match self.method_map.find(&name.name) {
             Some(candidate_traits) => loop {
                 // Look for the current trait.
                 match self.current_trait_refs {
@@ -5506,7 +5508,7 @@ pub fn dump_module(@mut self, module_: @mut Module) {
         debug!("Children:");
         self.populate_module_if_necessary(module_);
         for (&name, _) in module_.children.iter() {
-            debug!("* %s", self.session.str_of(name));
+            debug!("* %s", interner_get(name));
         }
 
         debug!("Import resolutions:");
@@ -5529,7 +5531,7 @@ pub fn dump_module(@mut self, module_: @mut Module) {
                 }
             }
 
-            debug!("* %s:%s%s", self.session.str_of(*name),
+            debug!("* %s:%s%s", interner_get(*name),
                    value_repr, type_repr);
         }
     }
@@ -5554,3 +5556,4 @@ pub fn resolve_crate(session: Session,
         trait_map: resolver.trait_map.clone(),
     }
 }
+
index 39e3e97b48947a7ecb306dc2f3e75bffece05e92..5efd81ebc474c289706909148e1f54a8865a10bc 100644 (file)
@@ -1482,7 +1482,7 @@ fn compile_submatch_continue(mut bcx: @mut Block,
             let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
             do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| {
                 let rec_vals = rec_fields.map(|field_name| {
-                        let ix = ty::field_idx_strict(tcx, *field_name, field_tys);
+                        let ix = ty::field_idx_strict(tcx, field_name.name, field_tys);
                         adt::trans_field_ptr(bcx, pat_repr, val, discr, ix)
                         });
                 compile_submatch(
@@ -2159,7 +2159,7 @@ fn bind_irrefutable_pat(bcx: @mut Block,
             let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
             do expr::with_field_tys(tcx, pat_ty, None) |discr, field_tys| {
                 for f in fields.iter() {
-                    let ix = ty::field_idx_strict(tcx, f.ident, field_tys);
+                    let ix = ty::field_idx_strict(tcx, f.ident.name, field_tys);
                     let fldptr = adt::trans_field_ptr(bcx, pat_repr, val,
                                                       discr, ix);
                     bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, binding_mode);
index 5f5db9b4487f5defa9cbc83ab7223c1bced6b3d0..9e281172b26114dd6ce3739d65d706ea9db9c979 100644 (file)
@@ -2648,10 +2648,10 @@ pub fn p2i(ccx: &CrateContext, v: ValueRef) -> ValueRef {
 }
 
 macro_rules! ifn (
-    ($name:expr, $args:expr, $ret:expr) => ({
+    ($intrinsics:ident, $name:expr, $args:expr, $ret:expr) => ({
         let name = $name;
         let f = decl_cdecl_fn(llmod, name, Type::func($args, &$ret));
-        intrinsics.insert(name, f);
+        $intrinsics.insert(name, f);
     })
 )
 
@@ -2659,135 +2659,136 @@ pub fn declare_intrinsics(llmod: ModuleRef) -> HashMap<&'static str, ValueRef> {
     let i8p = Type::i8p();
     let mut intrinsics = HashMap::new();
 
-    ifn!("llvm.memcpy.p0i8.p0i8.i32",
+    ifn!(intrinsics, "llvm.memcpy.p0i8.p0i8.i32",
          [i8p, i8p, Type::i32(), Type::i32(), Type::i1()], Type::void());
-    ifn!("llvm.memcpy.p0i8.p0i8.i64",
+    ifn!(intrinsics, "llvm.memcpy.p0i8.p0i8.i64",
          [i8p, i8p, Type::i64(), Type::i32(), Type::i1()], Type::void());
-    ifn!("llvm.memmove.p0i8.p0i8.i32",
+    ifn!(intrinsics, "llvm.memmove.p0i8.p0i8.i32",
          [i8p, i8p, Type::i32(), Type::i32(), Type::i1()], Type::void());
-    ifn!("llvm.memmove.p0i8.p0i8.i64",
+    ifn!(intrinsics, "llvm.memmove.p0i8.p0i8.i64",
          [i8p, i8p, Type::i64(), Type::i32(), Type::i1()], Type::void());
-    ifn!("llvm.memset.p0i8.i32",
+    ifn!(intrinsics, "llvm.memset.p0i8.i32",
          [i8p, Type::i8(), Type::i32(), Type::i32(), Type::i1()], Type::void());
-    ifn!("llvm.memset.p0i8.i64",
+    ifn!(intrinsics, "llvm.memset.p0i8.i64",
          [i8p, Type::i8(), Type::i64(), Type::i32(), Type::i1()], Type::void());
 
-    ifn!("llvm.trap", [], Type::void());
-    ifn!("llvm.frameaddress", [Type::i32()], i8p);
-
-    ifn!("llvm.powi.f32", [Type::f32(), Type::i32()], Type::f32());
-    ifn!("llvm.powi.f64", [Type::f64(), Type::i32()], Type::f64());
-    ifn!("llvm.pow.f32",  [Type::f32(), Type::f32()], Type::f32());
-    ifn!("llvm.pow.f64",  [Type::f64(), Type::f64()], Type::f64());
-
-    ifn!("llvm.sqrt.f32", [Type::f32()], Type::f32());
-    ifn!("llvm.sqrt.f64", [Type::f64()], Type::f64());
-    ifn!("llvm.sin.f32",  [Type::f32()], Type::f32());
-    ifn!("llvm.sin.f64",  [Type::f64()], Type::f64());
-    ifn!("llvm.cos.f32",  [Type::f32()], Type::f32());
-    ifn!("llvm.cos.f64",  [Type::f64()], Type::f64());
-    ifn!("llvm.exp.f32",  [Type::f32()], Type::f32());
-    ifn!("llvm.exp.f64",  [Type::f64()], Type::f64());
-    ifn!("llvm.exp2.f32", [Type::f32()], Type::f32());
-    ifn!("llvm.exp2.f64", [Type::f64()], Type::f64());
-    ifn!("llvm.log.f32",  [Type::f32()], Type::f32());
-    ifn!("llvm.log.f64",  [Type::f64()], Type::f64());
-    ifn!("llvm.log10.f32",[Type::f32()], Type::f32());
-    ifn!("llvm.log10.f64",[Type::f64()], Type::f64());
-    ifn!("llvm.log2.f32", [Type::f32()], Type::f32());
-    ifn!("llvm.log2.f64", [Type::f64()], Type::f64());
-
-    ifn!("llvm.fma.f32",  [Type::f32(), Type::f32(), Type::f32()], Type::f32());
-    ifn!("llvm.fma.f64",  [Type::f64(), Type::f64(), Type::f64()], Type::f64());
-
-    ifn!("llvm.fabs.f32", [Type::f32()], Type::f32());
-    ifn!("llvm.fabs.f64", [Type::f64()], Type::f64());
-    ifn!("llvm.floor.f32",[Type::f32()], Type::f32());
-    ifn!("llvm.floor.f64",[Type::f64()], Type::f64());
-    ifn!("llvm.ceil.f32", [Type::f32()], Type::f32());
-    ifn!("llvm.ceil.f64", [Type::f64()], Type::f64());
-    ifn!("llvm.trunc.f32",[Type::f32()], Type::f32());
-    ifn!("llvm.trunc.f64",[Type::f64()], Type::f64());
-
-    ifn!("llvm.ctpop.i8", [Type::i8()], Type::i8());
-    ifn!("llvm.ctpop.i16",[Type::i16()], Type::i16());
-    ifn!("llvm.ctpop.i32",[Type::i32()], Type::i32());
-    ifn!("llvm.ctpop.i64",[Type::i64()], Type::i64());
-
-    ifn!("llvm.ctlz.i8",  [Type::i8() , Type::i1()], Type::i8());
-    ifn!("llvm.ctlz.i16", [Type::i16(), Type::i1()], Type::i16());
-    ifn!("llvm.ctlz.i32", [Type::i32(), Type::i1()], Type::i32());
-    ifn!("llvm.ctlz.i64", [Type::i64(), Type::i1()], Type::i64());
-
-    ifn!("llvm.cttz.i8",  [Type::i8() , Type::i1()], Type::i8());
-    ifn!("llvm.cttz.i16", [Type::i16(), Type::i1()], Type::i16());
-    ifn!("llvm.cttz.i32", [Type::i32(), Type::i1()], Type::i32());
-    ifn!("llvm.cttz.i64", [Type::i64(), Type::i1()], Type::i64());
-
-    ifn!("llvm.bswap.i16",[Type::i16()], Type::i16());
-    ifn!("llvm.bswap.i32",[Type::i32()], Type::i32());
-    ifn!("llvm.bswap.i64",[Type::i64()], Type::i64());
-
-    ifn!("llvm.sadd.with.overflow.i8",
+    ifn!(intrinsics, "llvm.trap", [], Type::void());
+    ifn!(intrinsics, "llvm.frameaddress", [Type::i32()], i8p);
+
+    ifn!(intrinsics, "llvm.powi.f32", [Type::f32(), Type::i32()], Type::f32());
+    ifn!(intrinsics, "llvm.powi.f64", [Type::f64(), Type::i32()], Type::f64());
+    ifn!(intrinsics, "llvm.pow.f32",  [Type::f32(), Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.pow.f64",  [Type::f64(), Type::f64()], Type::f64());
+
+    ifn!(intrinsics, "llvm.sqrt.f32", [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.sqrt.f64", [Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.sin.f32",  [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.sin.f64",  [Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.cos.f32",  [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.cos.f64",  [Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.exp.f32",  [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.exp.f64",  [Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.exp2.f32", [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.exp2.f64", [Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.log.f32",  [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.log.f64",  [Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.log10.f32",[Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.log10.f64",[Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.log2.f32", [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.log2.f64", [Type::f64()], Type::f64());
+
+    ifn!(intrinsics, "llvm.fma.f32",  [Type::f32(), Type::f32(), Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.fma.f64",  [Type::f64(), Type::f64(), Type::f64()], Type::f64());
+
+    ifn!(intrinsics, "llvm.fabs.f32", [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.fabs.f64", [Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.floor.f32",[Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.floor.f64",[Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.ceil.f32", [Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.ceil.f64", [Type::f64()], Type::f64());
+    ifn!(intrinsics, "llvm.trunc.f32",[Type::f32()], Type::f32());
+    ifn!(intrinsics, "llvm.trunc.f64",[Type::f64()], Type::f64());
+
+    ifn!(intrinsics, "llvm.ctpop.i8", [Type::i8()], Type::i8());
+    ifn!(intrinsics, "llvm.ctpop.i16",[Type::i16()], Type::i16());
+    ifn!(intrinsics, "llvm.ctpop.i32",[Type::i32()], Type::i32());
+    ifn!(intrinsics, "llvm.ctpop.i64",[Type::i64()], Type::i64());
+
+    ifn!(intrinsics, "llvm.ctlz.i8",  [Type::i8() , Type::i1()], Type::i8());
+    ifn!(intrinsics, "llvm.ctlz.i16", [Type::i16(), Type::i1()], Type::i16());
+    ifn!(intrinsics, "llvm.ctlz.i32", [Type::i32(), Type::i1()], Type::i32());
+    ifn!(intrinsics, "llvm.ctlz.i64", [Type::i64(), Type::i1()], Type::i64());
+
+    ifn!(intrinsics, "llvm.cttz.i8",  [Type::i8() , Type::i1()], Type::i8());
+    ifn!(intrinsics, "llvm.cttz.i16", [Type::i16(), Type::i1()], Type::i16());
+    ifn!(intrinsics, "llvm.cttz.i32", [Type::i32(), Type::i1()], Type::i32());
+    ifn!(intrinsics, "llvm.cttz.i64", [Type::i64(), Type::i1()], Type::i64());
+
+    ifn!(intrinsics, "llvm.bswap.i16",[Type::i16()], Type::i16());
+    ifn!(intrinsics, "llvm.bswap.i32",[Type::i32()], Type::i32());
+    ifn!(intrinsics, "llvm.bswap.i64",[Type::i64()], Type::i64());
+
+    ifn!(intrinsics, "llvm.sadd.with.overflow.i8",
         [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
-    ifn!("llvm.sadd.with.overflow.i16",
+    ifn!(intrinsics, "llvm.sadd.with.overflow.i16",
         [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
-    ifn!("llvm.sadd.with.overflow.i32",
+    ifn!(intrinsics, "llvm.sadd.with.overflow.i32",
         [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
-    ifn!("llvm.sadd.with.overflow.i64",
+    ifn!(intrinsics, "llvm.sadd.with.overflow.i64",
         [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
 
-    ifn!("llvm.uadd.with.overflow.i8",
+    ifn!(intrinsics, "llvm.uadd.with.overflow.i8",
         [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
-    ifn!("llvm.uadd.with.overflow.i16",
+    ifn!(intrinsics, "llvm.uadd.with.overflow.i16",
         [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
-    ifn!("llvm.uadd.with.overflow.i32",
+    ifn!(intrinsics, "llvm.uadd.with.overflow.i32",
         [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
-    ifn!("llvm.uadd.with.overflow.i64",
+    ifn!(intrinsics, "llvm.uadd.with.overflow.i64",
         [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
 
-    ifn!("llvm.ssub.with.overflow.i8",
+    ifn!(intrinsics, "llvm.ssub.with.overflow.i8",
         [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
-    ifn!("llvm.ssub.with.overflow.i16",
+    ifn!(intrinsics, "llvm.ssub.with.overflow.i16",
         [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
-    ifn!("llvm.ssub.with.overflow.i32",
+    ifn!(intrinsics, "llvm.ssub.with.overflow.i32",
         [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
-    ifn!("llvm.ssub.with.overflow.i64",
+    ifn!(intrinsics, "llvm.ssub.with.overflow.i64",
         [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
 
-    ifn!("llvm.usub.with.overflow.i8",
+    ifn!(intrinsics, "llvm.usub.with.overflow.i8",
         [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
-    ifn!("llvm.usub.with.overflow.i16",
+    ifn!(intrinsics, "llvm.usub.with.overflow.i16",
         [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
-    ifn!("llvm.usub.with.overflow.i32",
+    ifn!(intrinsics, "llvm.usub.with.overflow.i32",
         [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
-    ifn!("llvm.usub.with.overflow.i64",
+    ifn!(intrinsics, "llvm.usub.with.overflow.i64",
         [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
 
-    ifn!("llvm.smul.with.overflow.i8",
+    ifn!(intrinsics, "llvm.smul.with.overflow.i8",
         [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
-    ifn!("llvm.smul.with.overflow.i16",
+    ifn!(intrinsics, "llvm.smul.with.overflow.i16",
         [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
-    ifn!("llvm.smul.with.overflow.i32",
+    ifn!(intrinsics, "llvm.smul.with.overflow.i32",
         [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
-    ifn!("llvm.smul.with.overflow.i64",
+    ifn!(intrinsics, "llvm.smul.with.overflow.i64",
         [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
 
-    ifn!("llvm.umul.with.overflow.i8",
+    ifn!(intrinsics, "llvm.umul.with.overflow.i8",
         [Type::i8(), Type::i8()], Type::struct_([Type::i8(), Type::i1()], false));
-    ifn!("llvm.umul.with.overflow.i16",
+    ifn!(intrinsics, "llvm.umul.with.overflow.i16",
         [Type::i16(), Type::i16()], Type::struct_([Type::i16(), Type::i1()], false));
-    ifn!("llvm.umul.with.overflow.i32",
+    ifn!(intrinsics, "llvm.umul.with.overflow.i32",
         [Type::i32(), Type::i32()], Type::struct_([Type::i32(), Type::i1()], false));
-    ifn!("llvm.umul.with.overflow.i64",
+    ifn!(intrinsics, "llvm.umul.with.overflow.i64",
         [Type::i64(), Type::i64()], Type::struct_([Type::i64(), Type::i1()], false));
 
     return intrinsics;
 }
 
 pub fn declare_dbg_intrinsics(llmod: ModuleRef, intrinsics: &mut HashMap<&'static str, ValueRef>) {
-    ifn!("llvm.dbg.declare", [Type::metadata(), Type::metadata()], Type::void());
-    ifn!("llvm.dbg.value",   [Type::metadata(), Type::i64(), Type::metadata()], Type::void());
+    ifn!(intrinsics, "llvm.dbg.declare", [Type::metadata(), Type::metadata()], Type::void());
+    ifn!(intrinsics,
+         "llvm.dbg.value",   [Type::metadata(), Type::i64(), Type::metadata()], Type::void());
 }
 
 pub fn trap(bcx: @mut Block) {
index 096e37136ac956a0437435fa81292fb9d0cc0761..94f0b3735700101ab3a7066975ece2290edca1c3 100644 (file)
@@ -374,7 +374,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
               let brepr = adt::represent_type(cx, bt);
               let bv = const_expr(cx, base);
               do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| {
-                  let ix = ty::field_idx_strict(cx.tcx, field, field_tys);
+                  let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
                   adt::const_get_field(cx, brepr, bv, discr, ix)
               }
           }
@@ -502,7 +502,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                   |discr, field_tys| {
                   let cs: ~[ValueRef] = field_tys.iter().enumerate()
                       .map(|(ix, &field_ty)| {
-                      match fs.iter().find(|f| field_ty.ident == f.ident) {
+                      match fs.iter().find(|f| field_ty.ident.name == f.ident.name) {
                           Some(f) => const_expr(cx, (*f).expr),
                           None => {
                               match base_val {
index 59159f61f485f1db385bc3eacd45347f53ae31af..6eb2fcf25fd3c289ff9113aa4c877ccd16099668 100644 (file)
@@ -87,7 +87,7 @@ pub struct CrateContext {
      // Cache of external const values
      extern_const_values: HashMap<ast::DefId, ValueRef>,
 
-     impl_method_cache: HashMap<(ast::DefId, ast::Ident), ast::DefId>,
+     impl_method_cache: HashMap<(ast::DefId, ast::Name), ast::DefId>,
 
      module_data: HashMap<~str, ValueRef>,
      lltypes: HashMap<ty::t, Type>,
index 646f71ec28ad23aa82079a1b062ef74c7a061d4f..e4879ef4a11da0666c595ebe024670e2158fe425 100644 (file)
@@ -1012,7 +1012,7 @@ fn struct_metadata(cx: &mut CrateContext,
 
     let field_llvm_types = do fields.map |field| { type_of::type_of(cx, field.mt.ty) };
     let field_names = do fields.map |field| {
-        if field.ident == special_idents::unnamed_field {
+        if field.ident.name == special_idents::unnamed_field.name {
             ~""
         } else {
             cx.sess.str_of(field.ident).to_owned()
@@ -1875,9 +1875,12 @@ fn walk_pattern(cx: &mut CrateContext,
                     // }
 
                     // Is there already a binding with that name?
+                    // N.B.: this comparison must be UNhygienic... because
+                    // gdb knows nothing about the context, so any two
+                    // variables with the same name will cause the problem.
                     let need_new_scope = scope_stack
                         .iter()
-                        .any(|entry| entry.ident.iter().any(|i| *i == ident));
+                        .any(|entry| entry.ident.iter().any(|i| i.name == ident.name));
 
                     if need_new_scope {
                         // Create a new lexical scope and push it onto the stack
index ce6fb6d3e7755c198c3b5f97f596c5b5a8bd33ee..819d390ac28b09ac6997cd5633ee2ebfdb39604a 100644 (file)
@@ -903,7 +903,7 @@ fn trans_rec_field(bcx: @mut Block,
         let base_datum = unpack_datum!(bcx, trans_to_datum(bcx, base));
         let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
         do with_field_tys(bcx.tcx(), base_datum.ty, None) |discr, field_tys| {
-            let ix = ty::field_idx_strict(bcx.tcx(), field, field_tys);
+            let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
             DatumBlock {
                 datum: do base_datum.get_element(bcx,
                                                  field_tys[ix].mt.ty,
@@ -1176,7 +1176,9 @@ fn trans_rec_or_struct(bcx: @mut Block,
         let mut need_base = vec::from_elem(field_tys.len(), true);
 
         let numbered_fields = do fields.map |field| {
-            let opt_pos = field_tys.iter().position(|field_ty| field_ty.ident == field.ident);
+            let opt_pos =
+                field_tys.iter().position(|field_ty|
+                                          field_ty.ident.name == field.ident.name);
             match opt_pos {
                 Some(i) => {
                     need_base[i] = false;
index 76b23d9d536aa56b32fba354e138cb30078fa97e..e49265a99a950a0aa46fd658fe6576752dc3e9fd 100644 (file)
@@ -268,7 +268,7 @@ pub fn trans_static_method_callee(bcx: @mut Block,
         typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
             assert!(rcvr_substs.iter().all(|t| !ty::type_needs_infer(*t)));
 
-            let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
+            let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name);
             let (callee_substs, callee_origins) =
                 combine_impl_and_methods_tps(
                     bcx, mth_id, callee_id,
@@ -294,7 +294,7 @@ pub fn trans_static_method_callee(bcx: @mut Block,
 
 pub fn method_with_name(ccx: &mut CrateContext,
                         impl_id: ast::DefId,
-                        name: ast::Ident) -> ast::DefId {
+                        name: ast::Name) -> ast::DefId {
     let meth_id_opt = ccx.impl_method_cache.find_copy(&(impl_id, name));
     match meth_id_opt {
         Some(m) => return m,
@@ -303,7 +303,7 @@ pub fn method_with_name(ccx: &mut CrateContext,
 
     let imp = ccx.tcx.impls.find(&impl_id)
         .expect("could not find impl while translating");
-    let meth = imp.methods.iter().find(|m| m.ident == name)
+    let meth = imp.methods.iter().find(|m| m.ident.name == name)
         .expect("could not find method while translating");
 
     ccx.impl_method_cache.insert((impl_id, name), meth.def_id);
@@ -323,7 +323,7 @@ pub fn trans_monomorphized_callee(bcx: @mut Block,
       typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => {
           let ccx = bcx.ccx();
           let mname = ty::trait_method(ccx.tcx, trait_id, n_method).ident;
-          let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
+          let mth_id = method_with_name(bcx.ccx(), impl_did, mname.name);
 
           // obtain the `self` value:
           let mut temp_cleanups = ~[];
@@ -600,7 +600,7 @@ fn emit_vtable_methods(bcx: @mut Block,
         let ident = ty::method(tcx, *method_def_id).ident;
         // The substitutions we have are on the impl, so we grab
         // the method type from the impl to substitute into.
-        let m_id = method_with_name(ccx, impl_id, ident);
+        let m_id = method_with_name(ccx, impl_id, ident.name);
         let m = ty::method(tcx, m_id);
         debug!("(making impl vtable) emitting method %s at subst %s",
                m.repr(tcx),
index 0958eeb7097a62a4b9b074110cfd0e6d3c28ccdc..4a42efc339328f8f2fbe008bfc0680ab1e024bb3 100644 (file)
@@ -3360,19 +3360,19 @@ pub fn stmt_node_id(s: &ast::Stmt) -> ast::NodeId {
     }
 }
 
-pub fn field_idx(id: ast::Ident, fields: &[field]) -> Option<uint> {
+pub fn field_idx(name: ast::Name, fields: &[field]) -> Option<uint> {
     let mut i = 0u;
-    for f in fields.iter() { if f.ident == id { return Some(i); } i += 1u; }
+    for f in fields.iter() { if f.ident.name == name { return Some(i); } i += 1u; }
     return None;
 }
 
-pub fn field_idx_strict(tcx: ty::ctxt, id: ast::Ident, fields: &[field])
+pub fn field_idx_strict(tcx: ty::ctxt, name: ast::Name, fields: &[field])
                      -> uint {
     let mut i = 0u;
-    for f in fields.iter() { if f.ident == id { return i; } i += 1u; }
+    for f in fields.iter() { if f.ident.name == name { return i; } i += 1u; }
     tcx.sess.bug(fmt!(
         "No field named `%s` found in the list of fields `%?`",
-        tcx.sess.str_of(id),
+        token::interner_get(name),
         fields.map(|f| tcx.sess.str_of(f.ident))));
 }
 
index d0beb5c609e89b09008db118f96f2adf3126e265..d813f97312340d58b9a9ba721b897ddc46a42985 100644 (file)
@@ -296,13 +296,13 @@ pub fn check_struct_pat_fields(pcx: &pat_ctxt,
     // Index the class fields.
     let mut field_map = HashMap::new();
     for (i, class_field) in class_fields.iter().enumerate() {
-        field_map.insert(class_field.ident, i);
+        field_map.insert(class_field.ident.name, i);
     }
 
     // Typecheck each field.
     let mut found_fields = HashSet::new();
     for field in fields.iter() {
-        match field_map.find(&field.ident) {
+        match field_map.find(&field.ident.name) {
             Some(&index) => {
                 let class_field = class_fields[index];
                 let field_type = ty::lookup_field_type(tcx,
index 3588fb3f51e71f421a8fe0c72775d87995337679..48d630b4aa93d57dcc508a1e64588da54f19598e 100644 (file)
@@ -105,6 +105,7 @@ trait `ToStr` imported, and I call `to_str()` on a value of type `T`,
 use syntax::ast::{MutMutable, MutImmutable};
 use syntax::ast;
 use syntax::ast_map;
+use syntax::parse::token;
 
 #[deriving(Eq)]
 pub enum CheckTraitsFlag {
@@ -126,7 +127,7 @@ pub fn lookup(
         self_expr: @ast::Expr,              // The expression `a`.
         callee_id: NodeId,                  /* Where to store `a.b`'s type,
                                              * also the scope of the call */
-        m_name: ast::Ident,                 // The ident `b`.
+        m_name: ast::Name,                  // The name `b`.
         self_ty: ty::t,                     // The type of `a`.
         supplied_tps: &[ty::t],             // The list of types X, Y, ... .
         deref_args: check::DerefArgs,       // Whether we autopointer first.
@@ -173,7 +174,7 @@ pub struct LookupContext<'self> {
     expr: @ast::Expr,
     self_expr: @ast::Expr,
     callee_id: NodeId,
-    m_name: ast::Ident,
+    m_name: ast::Name,
     supplied_tps: &'self [ty::t],
     impl_dups: @mut HashSet<DefId>,
     inherent_candidates: @mut ~[Candidate],
@@ -515,7 +516,7 @@ fn push_inherent_candidates_from_bounds_inner(
             let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id);
             match trait_methods.iter().position(|m| {
                 m.explicit_self != ast::sty_static &&
-                m.ident == self.m_name })
+                m.ident.name == self.m_name })
             {
                 Some(pos) => {
                     let method = trait_methods[pos];
@@ -558,12 +559,12 @@ fn push_candidates_from_impl(&self,
             return; // already visited
         }
         debug!("push_candidates_from_impl: %s %s %s",
-               self.m_name.repr(self.tcx()),
+               token::interner_get(self.m_name),
                impl_info.ident.repr(self.tcx()),
                impl_info.methods.map(|m| m.ident).repr(self.tcx()));
 
         let idx = {
-            match impl_info.methods.iter().position(|m| m.ident == self.m_name) {
+            match impl_info.methods.iter().position(|m| m.ident.name == self.m_name) {
                 Some(idx) => idx,
                 None => { return; } // No method with the right name.
             }
index 0e335cf3f145d48e79f5328879a26bd0aeee67ae..50c93468bb1619ade57c11771e6a1e0a246200ab 100644 (file)
@@ -1117,10 +1117,10 @@ pub fn impl_self_ty(vcx: &VtableContext,
 pub fn lookup_field_ty(tcx: ty::ctxt,
                        class_id: ast::DefId,
                        items: &[ty::field_ty],
-                       fieldname: ast::Ident,
+                       fieldname: ast::Name,
                        substs: &ty::substs) -> Option<ty::t> {
 
-    let o_field = items.iter().find(|f| f.ident == fieldname);
+    let o_field = items.iter().find(|f| f.ident.name == fieldname);
     do o_field.map() |f| {
         ty::lookup_field_type(tcx, class_id, f.id, substs)
     }
@@ -1553,7 +1553,7 @@ fn check_method_call(fcx: @mut FnCtxt,
                              expr,
                              rcvr,
                              callee_id,
-                             method_name,
+                             method_name.name,
                              expr_t,
                              tps,
                              DontDerefArgs,
@@ -1637,7 +1637,7 @@ fn lookup_op_method(fcx: @mut FnCtxt,
                         op_ex: @ast::Expr,
                         self_ex: @ast::Expr,
                         self_t: ty::t,
-                        opname: ast::Ident,
+                        opname: ast::Name,
                         args: ~[@ast::Expr],
                         deref_args: DerefArgs,
                         autoderef_receiver: AutoderefReceiverFlag,
@@ -1777,7 +1777,7 @@ fn check_user_binop(fcx: @mut FnCtxt,
                             lhs_resolved_t, None)
                 };
                 return lookup_op_method(fcx, callee_id, ex, lhs_expr, lhs_resolved_t,
-                                       fcx.tcx().sess.ident_of(*name),
+                                       token::intern(*name),
                                        ~[rhs], DoDerefArgs, DontAutoderefReceiver, if_op_unbound,
                                        expected_result);
             }
@@ -1811,7 +1811,7 @@ fn check_user_unop(fcx: @mut FnCtxt,
                     -> ty::t {
        lookup_op_method(
             fcx, callee_id, ex, rhs_expr, rhs_t,
-            fcx.tcx().sess.ident_of(mname), ~[],
+            token::intern(mname), ~[],
             DoDerefArgs, DontAutoderefReceiver,
             || {
                 fcx.type_error_message(ex.span, |actual| {
@@ -1937,7 +1937,7 @@ fn check_expr_fn(fcx: @mut FnCtxt,
     fn check_field(fcx: @mut FnCtxt,
                    expr: @ast::Expr,
                    base: @ast::Expr,
-                   field: ast::Ident,
+                   field: ast::Name,
                    tys: &[ast::Ty]) {
         let tcx = fcx.ccx.tcx;
         let bot = check_expr(fcx, base);
@@ -1985,7 +1985,7 @@ fn check_field(fcx: @mut FnCtxt,
                     |actual| {
                         fmt!("attempted to take value of method `%s` on type `%s` \
                               (try writing an anonymous function)",
-                             tcx.sess.str_of(field), actual)
+                             token::interner_get(field), actual)
                     },
                     expr_t, None);
             }
@@ -1996,7 +1996,7 @@ fn check_field(fcx: @mut FnCtxt,
                     |actual| {
                         fmt!("attempted access of field `%s` on type `%s`, \
                               but no field with that name was found",
-                             tcx.sess.str_of(field), actual)
+                             token::interner_get(field), actual)
                     },
                     expr_t, None);
             }
@@ -2018,7 +2018,7 @@ fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
         let mut class_field_map = HashMap::new();
         let mut fields_found = 0;
         for field in field_types.iter() {
-            class_field_map.insert(field.ident, (field.id, false));
+            class_field_map.insert(field.ident.name, (field.id, false));
         }
 
         let mut error_happened = false;
@@ -2027,7 +2027,7 @@ fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
         for field in ast_fields.iter() {
             let mut expected_field_type = ty::mk_err();
 
-            let pair = class_field_map.find(&field.ident).map_move(|x| *x);
+            let pair = class_field_map.find(&field.ident.name).map_move(|x| *x);
             match pair {
                 None => {
                     tcx.sess.span_err(
@@ -2048,7 +2048,7 @@ fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
                         ty::lookup_field_type(
                             tcx, class_id, field_id, &substitutions);
                     class_field_map.insert(
-                        field.ident, (field_id, true));
+                        field.ident.name, (field_id, true));
                     fields_found += 1;
                 }
             }
@@ -2070,11 +2070,11 @@ fn check_struct_or_variant_fields(fcx: @mut FnCtxt,
             if fields_found < field_types.len() {
                 let mut missing_fields = ~[];
                 for class_field in field_types.iter() {
-                    let name = class_field.ident;
+                    let name = class_field.ident.name;
                     let (_, seen) = *class_field_map.get(&name);
                     if !seen {
                         missing_fields.push(
-                            ~"`" + tcx.sess.str_of(name) + "`");
+                            ~"`" + token::interner_get(name) + "`");
                     }
                 }
 
@@ -2846,7 +2846,7 @@ fn types_compatible(fcx: @mut FnCtxt, sp: Span,
         }
       }
       ast::ExprField(base, field, ref tys) => {
-        check_field(fcx, expr, base, field, *tys);
+        check_field(fcx, expr, base, field.name, *tys);
       }
       ast::ExprIndex(callee_id, base, idx) => {
           check_expr(fcx, base);
@@ -2886,7 +2886,7 @@ fn types_compatible(fcx: @mut FnCtxt, sp: Span,
                                                     expr,
                                                     base,
                                                     resolved,
-                                                    index_ident,
+                                                    index_ident.name,
                                                     ~[idx],
                                                     DoDerefArgs,
                                                     AutoderefReceiver,
index 738ed9656e38724ba940cb65470c4d1626ec9925..700b60f1159a6ba9bbf70e0d8586c1d46f4d519e 100644 (file)
@@ -553,13 +553,13 @@ pub fn check_trait_methods_are_implemented(
         let mut provided_names = HashSet::new();
         // Implemented methods
         for elt in all_methods.iter() {
-            provided_names.insert(elt.ident);
+            provided_names.insert(elt.ident.name);
         }
 
         let r = ty::trait_methods(tcx, trait_did);
         for method in r.iter() {
             debug!("checking for %s", method.ident.repr(tcx));
-            if provided_names.contains(&method.ident) { loop; }
+            if provided_names.contains(&method.ident.name) { loop; }
 
             tcx.sess.span_err(trait_ref_span,
                               fmt!("missing method `%s`",
index 8056831537f59b99154e1e9ca97dc503559b0c7a..3f5e1ef52108827e32d87ee40d73832224231234 100644 (file)
@@ -698,7 +698,7 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt,
     // we'll catch it in coherence
     let trait_ms = ty::trait_methods(tcx, trait_ref.def_id);
     for impl_m in impl_ms.iter() {
-        match trait_ms.iter().find(|trait_m| trait_m.ident == impl_m.mty.ident) {
+        match trait_ms.iter().find(|trait_m| trait_m.ident.name == impl_m.mty.ident.name) {
             Some(trait_m) => {
                 let num_impl_tps = generics.ty_params.len();
                 compare_impl_method(
index 01f57c231dadef53cdab7b5ae1e8b05a6ead16b5..e3615b7b7db037fa06712fbc5893404aca1368d4 100644 (file)
@@ -375,3 +375,13 @@ fn to_bytes(&self, lsb0: bool) -> ~[u8] {
         }
     }
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    // just test to see if it compiles:
+    #[test] fn iterbytes_compiles () {
+        takes_iterbytes((3,4,5,false));
+    }
+    fn takes_iterbytes<T : IterBytes>(x : T) {}
+}
index c7ebc344a9c870fffe5b806668e0548681c46057..b993f98ec82b16d735941c13b037fd120a5371c8 100644 (file)
 use std::to_str::ToStr;
 use extra::serialize::{Encodable, Decodable, Encoder, Decoder};
 
+
+// FIXME #6993: in librustc, uses of "ident" should be replaced
+// by just "Name".
+
 // an identifier contains a Name (index into the interner
 // table) and a SyntaxContext to track renaming and
 // macro expansion per Flatt et al., "Macros
@@ -32,6 +36,36 @@ impl Ident {
     pub fn new(name: Name) -> Ident { Ident {name: name, ctxt: EMPTY_CTXT}}
 }
 
+// defining eq in this way is a way of guaranteeing that later stages of the
+// compiler don't compare identifiers unhygienically. Unfortunately, some tests
+// (specifically debuginfo in no-opt) want to do these comparisons, and that
+// seems fine.  If only I could find a nice way to statically ensure that
+// the compiler "proper" never compares identifiers.... I'm leaving this
+// code here (commented out) for potential use in debugging. Specifically, if
+// there's a bug where "identifiers aren't matching", it may be because
+// they should be compared using mtwt_resolve. In such a case, re-enabling this
+// code (and disabling deriving(Eq) for Idents) could help to isolate the
+// problem
+/* impl Eq for Ident {
+    fn eq(&self, other: &Ident) -> bool {
+        if (self.ctxt == other.ctxt) {
+            self.name == other.name
+        } else {
+            // IF YOU SEE ONE OF THESE FAILS: it means that you're comparing
+            // idents that have different contexts. You can't fix this without
+            // knowing whether the comparison should be hygienic or non-hygienic.
+            // if it should be non-hygienic (most things are), just compare the
+            // 'name' fields of the idents. Or, even better, replace the idents
+            // with Name's.
+            fail!(fmt!("not allowed to compare these idents: %?, %?", self, other));
+        }
+    }
+    fn ne(&self, other: &Ident) -> bool {
+        ! self.eq(other)
+    }
+}
+*/
+
 /// A SyntaxContext represents a chain of macro-expandings
 /// and renamings. Each macro expansion corresponds to
 /// a fresh uint
@@ -47,6 +81,15 @@ pub fn new(name: Name) -> Ident { Ident {name: name, ctxt: EMPTY_CTXT}}
 // storage.
 pub type SyntaxContext = uint;
 
+// the SCTable contains a table of SyntaxContext_'s. It
+// represents a flattened tree structure, to avoid having
+// managed pointers everywhere (that caused an ICE).
+// the mark_memo and rename_memo fields are side-tables
+// that ensure that adding the same mark to the same context
+// gives you back the same context as before. This shouldn't
+// change the semantics--everything here is immutable--but
+// it should cut down on memory use *a lot*; applying a mark
+// to a tree containing 50 identifiers would otherwise generate
 pub struct SCTable {
     table : ~[SyntaxContext_],
     mark_memo : HashMap<(SyntaxContext,Mrk),SyntaxContext>,
@@ -70,6 +113,7 @@ pub enum SyntaxContext_ {
     // in the "from" slot. In essence, they're all
     // pointers to a single "rename" event node.
     Rename (Ident,Name,SyntaxContext),
+    // actually, IllegalCtxt may not be necessary.
     IllegalCtxt
 }
 
@@ -99,6 +143,7 @@ fn decode(d: &mut D) -> Ident {
 pub struct Lifetime {
     id: NodeId,
     span: Span,
+    // FIXME #7743 : change this to Name!
     ident: Ident
 }
 
@@ -443,7 +488,7 @@ pub enum BlockCheckMode {
     UnsafeBlock,
 }
 
-#[deriving(Eq, Encodable, Decodable,IterBytes)]
+#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
 pub struct Expr {
     id: NodeId,
     node: Expr_,
@@ -544,10 +589,11 @@ pub enum token_tree {
     // a delimited sequence (the delimiters appear as the first
     // and last elements of the vector)
     tt_delim(@mut ~[token_tree]),
+
     // These only make sense for right-hand-sides of MBE macros:
 
     // a kleene-style repetition sequence with a span, a tt_forest,
-    // an optional separator (?), and a boolean where true indicates
+    // an optional separator, and a boolean where true indicates
     // zero or more (*), and false indicates one or more (+).
     tt_seq(Span, @mut ~[token_tree], Option<::parse::token::Token>, bool),
 
@@ -622,9 +668,13 @@ pub enum matcher_ {
 
 pub type mac = Spanned<mac_>;
 
+// represents a macro invocation. The Path indicates which macro
+// is being invoked, and the vector of token-trees contains the source
+// of the macro invocation.
+// There's only one flavor, now, so this could presumably be simplified.
 #[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
 pub enum mac_ {
-    mac_invoc_tt(Path,~[token_tree]),   // new macro-invocation
+    mac_invoc_tt(Path,~[token_tree],SyntaxContext),   // new macro-invocation
 }
 
 pub type lit = Spanned<lit_>;
index 5ee8537750ed508193864ff7090e42d56fcbca77..ee898c182e08a6f779d6a873a32997f03da81619 100644 (file)
@@ -28,6 +28,8 @@ pub fn path_name_i(idents: &[Ident]) -> ~str {
     idents.map(|i| token::interner_get(i.name)).connect("::")
 }
 
+// totally scary function: ignores all but the last element, should have
+// a different name
 pub fn path_to_ident(path: &Path) -> Ident {
     path.segments.last().identifier
 }
@@ -825,9 +827,6 @@ pub fn pat_is_ident(pat: @ast::Pat) -> bool {
 
 // HYGIENE FUNCTIONS
 
-/// Construct an identifier with the given name and an empty context:
-pub fn new_ident(name: Name) -> Ident { Ident {name: name, ctxt: 0}}
-
 /// Extend a syntax context with a given mark
 pub fn new_mark(m:Mrk, tail:SyntaxContext) -> SyntaxContext {
     new_mark_internal(m,tail,get_sctable())
@@ -908,6 +907,15 @@ pub fn get_sctable() -> @mut SCTable {
     }
 }
 
+/// print out an SCTable for debugging
+pub fn display_sctable(table : &SCTable) {
+    error!("SC table:");
+    for (idx,val) in table.table.iter().enumerate() {
+        error!("%4u : %?",idx,val);
+    }
+}
+
+
 /// Add a value to the end of a vec, return its index
 fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {
     vec.push(val);
@@ -915,35 +923,76 @@ fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {
 }
 
 /// Resolve a syntax object to a name, per MTWT.
-pub fn resolve(id : Ident) -> Name {
-    resolve_internal(id, get_sctable())
+pub fn mtwt_resolve(id : Ident) -> Name {
+    resolve_internal(id, get_sctable(), get_resolve_table())
+}
+
+// FIXME #4536: must be pub for testing
+pub type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
+
+// okay, I admit, putting this in TLS is not so nice:
+// fetch the SCTable from TLS, create one if it doesn't yet exist.
+pub fn get_resolve_table() -> @mut ResolveTable {
+    static resolve_table_key: local_data::Key<@@mut ResolveTable> = &local_data::Key;
+    match local_data::get(resolve_table_key, |k| k.map(|&k| *k)) {
+        None => {
+            let new_table = @@mut HashMap::new();
+            local_data::set(resolve_table_key,new_table);
+            *new_table
+        },
+        Some(intr) => *intr
+    }
 }
 
 // Resolve a syntax object to a name, per MTWT.
+// adding memoization to possibly resolve 500+ seconds in resolve for librustc (!)
 // FIXME #4536 : currently pub to allow testing
-pub fn resolve_internal(id : Ident, table : &mut SCTable) -> Name {
-    match table.table[id.ctxt] {
-        EmptyCtxt => id.name,
-        // ignore marks here:
-        Mark(_,subctxt) => resolve_internal(Ident{name:id.name, ctxt: subctxt},table),
-        // do the rename if necessary:
-        Rename(Ident{name,ctxt},toname,subctxt) => {
-            // this could be cached or computed eagerly:
-            let resolvedfrom = resolve_internal(Ident{name:name,ctxt:ctxt},table);
-            let resolvedthis = resolve_internal(Ident{name:id.name,ctxt:subctxt},table);
-            if ((resolvedthis == resolvedfrom)
-                && (marksof(ctxt,resolvedthis,table)
-                    == marksof(subctxt,resolvedthis,table))) {
-                toname
-            } else {
-                resolvedthis
-            }
+pub fn resolve_internal(id : Ident,
+                        table : &mut SCTable,
+                        resolve_table : &mut ResolveTable) -> Name {
+    let key = (id.name,id.ctxt);
+    match resolve_table.contains_key(&key) {
+        false => {
+            let resolved = {
+                match table.table[id.ctxt] {
+                    EmptyCtxt => id.name,
+                    // ignore marks here:
+                    Mark(_,subctxt) =>
+                        resolve_internal(Ident{name:id.name, ctxt: subctxt},table,resolve_table),
+                    // do the rename if necessary:
+                    Rename(Ident{name,ctxt},toname,subctxt) => {
+                        let resolvedfrom =
+                            resolve_internal(Ident{name:name,ctxt:ctxt},table,resolve_table);
+                        let resolvedthis =
+                            resolve_internal(Ident{name:id.name,ctxt:subctxt},table,resolve_table);
+                        if ((resolvedthis == resolvedfrom)
+                            && (marksof(ctxt,resolvedthis,table)
+                                == marksof(subctxt,resolvedthis,table))) {
+                            toname
+                        } else {
+                            resolvedthis
+                        }
+                    }
+                    IllegalCtxt() => fail!(~"expected resolvable context, got IllegalCtxt")
+                }
+            };
+            resolve_table.insert(key,resolved);
+            resolved
+        }
+        true => {
+            // it's guaranteed to be there, because we just checked that it was
+            // there and we never remove anything from the table:
+            *(resolve_table.find(&key).unwrap())
         }
-        IllegalCtxt() => fail!(~"expected resolvable context, got IllegalCtxt")
     }
 }
 
 /// Compute the marks associated with a syntax context.
+pub fn mtwt_marksof(ctxt: SyntaxContext, stopname: Name) -> ~[Mrk] {
+    marksof(ctxt, stopname, get_sctable())
+}
+
+// the internal function for computing marks
 // it's not clear to me whether it's better to use a [] mutable
 // vector or a cons-list for this.
 pub fn marksof(ctxt: SyntaxContext, stopname: Name, table: &SCTable) -> ~[Mrk] {
@@ -970,6 +1019,16 @@ pub fn marksof(ctxt: SyntaxContext, stopname: Name, table: &SCTable) -> ~[Mrk] {
     }
 }
 
+/// Return the outer mark for a context with a mark at the outside.
+/// FAILS when outside is not a mark.
+pub fn mtwt_outer_mark(ctxt: SyntaxContext) -> Mrk {
+    let sctable = get_sctable();
+    match sctable.table[ctxt] {
+        ast::Mark(mrk,_) => mrk,
+        _ => fail!("can't retrieve outer mark when outside is not a mark")
+    }
+}
+
 /// Push a name... unless it matches the one on top, in which
 /// case pop and discard (so two of the same marks cancel)
 pub fn xorPush(marks: &mut ~[uint], mark: uint) {
@@ -986,12 +1045,55 @@ pub fn getLast(arr: &~[Mrk]) -> uint {
     *arr.last()
 }
 
+// are two paths equal when compared unhygienically?
+// since I'm using this to replace ==, it seems appropriate
+// to compare the span, global, etc. fields as well.
+pub fn path_name_eq(a : &ast::Path, b : &ast::Path) -> bool {
+    (a.span == b.span)
+    && (a.global == b.global)
+    && (segments_name_eq(a.segments, b.segments))
+}
+
+// are two arrays of segments equal when compared unhygienically?
+pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> bool {
+    if (a.len() != b.len()) {
+        false
+    } else {
+        for (idx,seg) in a.iter().enumerate() {
+            if (seg.identifier.name != b[idx].identifier.name)
+                // FIXME #7743: ident -> name problems in lifetime comparison?
+                || (seg.lifetime != b[idx].lifetime)
+                // can types contain idents?
+                || (seg.types != b[idx].types) {
+                return false;
+            }
+        }
+        true
+    }
+}
 
 #[cfg(test)]
 mod test {
     use ast::*;
     use super::*;
     use std::io;
+    use opt_vec;
+    use std::hash::HashMap;
+
+    fn ident_to_segment(id : &Ident) -> PathSegment {
+        PathSegment{identifier:id.clone(), lifetime: None, types: opt_vec::Empty}
+    }
+
+    #[test] fn idents_name_eq_test() {
+        assert!(segments_name_eq([Ident{name:3,ctxt:4},
+                                   Ident{name:78,ctxt:82}].map(ident_to_segment),
+                                 [Ident{name:3,ctxt:104},
+                                   Ident{name:78,ctxt:182}].map(ident_to_segment)));
+        assert!(!segments_name_eq([Ident{name:3,ctxt:4},
+                                    Ident{name:78,ctxt:82}].map(ident_to_segment),
+                                  [Ident{name:3,ctxt:104},
+                                    Ident{name:77,ctxt:182}].map(ident_to_segment)));
+    }
 
     #[test] fn xorpush_test () {
         let mut s = ~[];
@@ -1122,29 +1224,30 @@ fn unfold_marks(mrks:~[Mrk],tail:SyntaxContext,table: &mut SCTable) -> SyntaxCon
     #[test] fn resolve_tests () {
         let a = 40;
         let mut t = new_sctable_internal();
+        let mut rt = HashMap::new();
         // - ctxt is MT
-        assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t),a);
+        assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t, &mut rt),a);
         // - simple ignored marks
         { let sc = unfold_marks(~[1,2,3],EMPTY_CTXT,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t),a);}
+         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),a);}
         // - orthogonal rename where names don't match
         { let sc = unfold_test_sc(~[R(id(50,EMPTY_CTXT),51),M(12)],EMPTY_CTXT,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t),a);}
+         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),a);}
         // - rename where names do match, but marks don't
         { let sc1 = new_mark_internal(1,EMPTY_CTXT,&mut t);
          let sc = unfold_test_sc(~[R(id(a,sc1),50),
                                    M(1),
                                    M(2)],
                                  EMPTY_CTXT,&mut t);
-        assert_eq!(resolve_internal(id(a,sc),&mut t), a);}
+        assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), a);}
         // - rename where names and marks match
         { let sc1 = unfold_test_sc(~[M(1),M(2)],EMPTY_CTXT,&mut t);
          let sc = unfold_test_sc(~[R(id(a,sc1),50),M(1),M(2)],EMPTY_CTXT,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t), 50); }
+         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 50); }
         // - rename where names and marks match by literal sharing
         { let sc1 = unfold_test_sc(~[M(1),M(2)],EMPTY_CTXT,&mut t);
          let sc = unfold_test_sc(~[R(id(a,sc1),50)],sc1,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t), 50); }
+         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 50); }
         // - two renames of the same var.. can only happen if you use
         // local-expand to prevent the inner binding from being renamed
         // during the rename-pass caused by the first:
@@ -1152,22 +1255,28 @@ fn unfold_marks(mrks:~[Mrk],tail:SyntaxContext,table: &mut SCTable) -> SyntaxCon
         { let sc = unfold_test_sc(~[R(id(a,EMPTY_CTXT),50),
                                     R(id(a,EMPTY_CTXT),51)],
                                   EMPTY_CTXT,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t), 51); }
+         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 51); }
         // the simplest double-rename:
         { let a_to_a50 = new_rename_internal(id(a,EMPTY_CTXT),50,EMPTY_CTXT,&mut t);
          let a50_to_a51 = new_rename_internal(id(a,a_to_a50),51,a_to_a50,&mut t);
-         assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t),51);
+         assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t, &mut rt),51);
          // mark on the outside doesn't stop rename:
          let sc = new_mark_internal(9,a50_to_a51,&mut t);
-         assert_eq!(resolve_internal(id(a,sc),&mut t),51);
+         assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),51);
          // but mark on the inside does:
          let a50_to_a51_b = unfold_test_sc(~[R(id(a,a_to_a50),51),
                                               M(9)],
                                            a_to_a50,
                                            &mut t);
-         assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t),50);}
+         assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t, &mut rt),50);}
     }
 
+    #[test] fn mtwt_resolve_test(){
+        let a = 40;
+        assert_eq!(mtwt_resolve(id(a,EMPTY_CTXT)),a);
+    }
+
+
     #[test] fn hashing_tests () {
         let mut t = new_sctable_internal();
         assert_eq!(new_mark_internal(12,EMPTY_CTXT,&mut t),2);
@@ -1177,4 +1286,16 @@ fn unfold_marks(mrks:~[Mrk],tail:SyntaxContext,table: &mut SCTable) -> SyntaxCon
         // I'm assuming that the rename table will behave the same....
     }
 
+    #[test] fn resolve_table_hashing_tests() {
+        let mut t = new_sctable_internal();
+        let mut rt = HashMap::new();
+        assert_eq!(rt.len(),0);
+        resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
+        assert_eq!(rt.len(),1);
+        resolve_internal(id(39,EMPTY_CTXT),&mut t, &mut rt);
+        assert_eq!(rt.len(),2);
+        resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
+        assert_eq!(rt.len(),2);
+    }
+
 }
index 50683358f876aa91228d6534fbc81a41ea2b0b27..3d5d62aeadf1e99a7532ecde6c0c9f4e7395fe1f 100644 (file)
@@ -22,8 +22,7 @@
 
 // new-style macro! tt code:
 //
-//    SyntaxExpanderTT, SyntaxExpanderTTItem, MacResult,
-//    NormalTT, IdentTT
+//    MacResult, NormalTT, IdentTT
 //
 // also note that ast::mac used to have a bunch of extraneous cases and
 // is now probably a redundant AST node, can be merged with
@@ -34,33 +33,46 @@ pub struct MacroDef {
     ext: SyntaxExtension
 }
 
-pub type ItemDecorator = @fn(@ExtCtxt,
+// No context arg for an Item Decorator macro, simply because
+// adding it would require adding a ctxt field to all items.
+// we could do this if it turns out to be useful.
+
+pub type ItemDecoratorFun = @fn(@ExtCtxt,
                              Span,
                              @ast::MetaItem,
                              ~[@ast::item])
                           -> ~[@ast::item];
 
-pub struct SyntaxExpanderTT {
-    expander: SyntaxExpanderTTFun,
-    span: Option<Span>
-}
-
 pub type SyntaxExpanderTTFun = @fn(@ExtCtxt,
                                    Span,
-                                   &[ast::token_tree])
+                                   &[ast::token_tree],
+                                   ast::SyntaxContext)
                                 -> MacResult;
 
-pub struct SyntaxExpanderTTItem {
-    expander: SyntaxExpanderTTItemFun,
-    span: Option<Span>
-}
-
 pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt,
+                                       Span,
+                                       ast::Ident,
+                                       ~[ast::token_tree],
+                                       ast::SyntaxContext)
+                                    -> MacResult;
+
+// oog... in order to make the presentation of builtin_normal_tt_no_ctxt
+// and builtin_ident_tt_no_ctxt palatable, we need one-off types for
+// functions that don't consume a ctxt:
+
+pub type SyntaxExpanderTTFunNoCtxt = @fn(@ExtCtxt,
+                                   Span,
+                                   &[ast::token_tree])
+                                -> MacResult;
+
+pub type SyntaxExpanderTTItemFunNoCtxt = @fn(@ExtCtxt,
                                        Span,
                                        ast::Ident,
                                        ~[ast::token_tree])
                                     -> MacResult;
 
+
+
 pub enum MacResult {
     MRExpr(@ast::Expr),
     MRItem(@ast::item),
@@ -73,10 +85,10 @@ pub enum MacResult {
 pub enum SyntaxExtension {
 
     // #[auto_encode] and such
-    ItemDecorator(ItemDecorator),
+    ItemDecorator(ItemDecoratorFun),
 
     // Token-tree expanders
-    NormalTT(SyntaxExpanderTT),
+    NormalTT(SyntaxExpanderTTFun, Option<Span>),
 
     // An IdentTT is a macro that has an
     // identifier in between the name of the
@@ -86,9 +98,10 @@ pub enum SyntaxExtension {
 
     // perhaps macro_rules! will lose its odd special identifier argument,
     // and this can go away also
-    IdentTT(SyntaxExpanderTTItem),
+    IdentTT(SyntaxExpanderTTItemFun, Option<Span>),
 }
 
+
 // The SyntaxEnv is the environment that's threaded through the expansion
 // of macros. It contains bindings for macros, and also a special binding
 // for " block" (not a legal identifier) that maps to a BlockInfo
@@ -120,12 +133,16 @@ pub struct BlockInfo {
 // AST nodes into full ASTs
 pub fn syntax_expander_table() -> SyntaxEnv {
     // utility function to simplify creating NormalTT syntax extensions
-    fn builtin_normal_tt(f: SyntaxExpanderTTFun) -> @Transformer {
-        @SE(NormalTT(SyntaxExpanderTT{expander: f, span: None}))
+    // that ignore their contexts
+    fn builtin_normal_tt_no_ctxt(f: SyntaxExpanderTTFunNoCtxt) -> @Transformer {
+        let wrapped_expander : SyntaxExpanderTTFun = |a,b,c,_d|{f(a,b,c)};
+        @SE(NormalTT(wrapped_expander, None))
     }
     // utility function to simplify creating IdentTT syntax extensions
-    fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
-        @SE(IdentTT(SyntaxExpanderTTItem{expander: f, span: None}))
+    // that ignore their contexts
+    fn builtin_item_tt_no_ctxt(f: SyntaxExpanderTTItemFunNoCtxt) -> @Transformer {
+        let wrapped_expander : SyntaxExpanderTTItemFun = |a,b,c,d,_e|{f(a,b,c,d)};
+        @SE(IdentTT(wrapped_expander, None))
     }
     let mut syntax_expanders = HashMap::new();
     // NB identifier starts with space, and can't conflict with legal idents
@@ -135,16 +152,15 @@ fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
                                 pending_renames : @mut ~[]
                             }));
     syntax_expanders.insert(intern(&"macro_rules"),
-                            builtin_item_tt(
-                                ext::tt::macro_rules::add_new_extension));
+                            @SE(IdentTT(ext::tt::macro_rules::add_new_extension, None)));
     syntax_expanders.insert(intern(&"fmt"),
-                            builtin_normal_tt(ext::fmt::expand_syntax_ext));
+                            builtin_normal_tt_no_ctxt(ext::fmt::expand_syntax_ext));
     syntax_expanders.insert(intern(&"format"),
-                            builtin_normal_tt(ext::ifmt::expand_format));
+                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_format));
     syntax_expanders.insert(intern(&"write"),
-                            builtin_normal_tt(ext::ifmt::expand_write));
+                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_write));
     syntax_expanders.insert(intern(&"writeln"),
-                            builtin_normal_tt(ext::ifmt::expand_writeln));
+                            builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln));
     syntax_expanders.insert(
         intern(&"auto_encode"),
         @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
@@ -152,16 +168,16 @@ fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
         intern(&"auto_decode"),
         @SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
     syntax_expanders.insert(intern(&"env"),
-                            builtin_normal_tt(ext::env::expand_env));
+                            builtin_normal_tt_no_ctxt(ext::env::expand_env));
     syntax_expanders.insert(intern(&"option_env"),
-                            builtin_normal_tt(ext::env::expand_option_env));
+                            builtin_normal_tt_no_ctxt(ext::env::expand_option_env));
     syntax_expanders.insert(intern("bytes"),
-                            builtin_normal_tt(ext::bytes::expand_syntax_ext));
+                            builtin_normal_tt_no_ctxt(ext::bytes::expand_syntax_ext));
     syntax_expanders.insert(intern("concat_idents"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::concat_idents::expand_syntax_ext));
     syntax_expanders.insert(intern(&"log_syntax"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::log_syntax::expand_syntax_ext));
     syntax_expanders.insert(intern(&"deriving"),
                             @SE(ItemDecorator(
@@ -169,49 +185,50 @@ fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
 
     // Quasi-quoting expanders
     syntax_expanders.insert(intern(&"quote_tokens"),
-                       builtin_normal_tt(ext::quote::expand_quote_tokens));
+                            builtin_normal_tt_no_ctxt(
+                                ext::quote::expand_quote_tokens));
     syntax_expanders.insert(intern(&"quote_expr"),
-                       builtin_normal_tt(ext::quote::expand_quote_expr));
+                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_expr));
     syntax_expanders.insert(intern(&"quote_ty"),
-                       builtin_normal_tt(ext::quote::expand_quote_ty));
+                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_ty));
     syntax_expanders.insert(intern(&"quote_item"),
-                       builtin_normal_tt(ext::quote::expand_quote_item));
+                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_item));
     syntax_expanders.insert(intern(&"quote_pat"),
-                       builtin_normal_tt(ext::quote::expand_quote_pat));
+                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_pat));
     syntax_expanders.insert(intern(&"quote_stmt"),
-                       builtin_normal_tt(ext::quote::expand_quote_stmt));
+                            builtin_normal_tt_no_ctxt(ext::quote::expand_quote_stmt));
 
     syntax_expanders.insert(intern(&"line"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_line));
     syntax_expanders.insert(intern(&"col"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_col));
     syntax_expanders.insert(intern(&"file"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_file));
     syntax_expanders.insert(intern(&"stringify"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_stringify));
     syntax_expanders.insert(intern(&"include"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_include));
     syntax_expanders.insert(intern(&"include_str"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_include_str));
     syntax_expanders.insert(intern(&"include_bin"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_include_bin));
     syntax_expanders.insert(intern(&"module_path"),
-                            builtin_normal_tt(
+                            builtin_normal_tt_no_ctxt(
                                 ext::source_util::expand_mod));
     syntax_expanders.insert(intern(&"asm"),
-                            builtin_normal_tt(ext::asm::expand_asm));
+                            builtin_normal_tt_no_ctxt(ext::asm::expand_asm));
     syntax_expanders.insert(intern(&"cfg"),
-                            builtin_normal_tt(ext::cfg::expand_cfg));
+                            builtin_normal_tt_no_ctxt(ext::cfg::expand_cfg));
     syntax_expanders.insert(
         intern(&"trace_macros"),
-        builtin_normal_tt(ext::trace_macros::expand_trace_macros));
+        builtin_normal_tt_no_ctxt(ext::trace_macros::expand_trace_macros));
     MapChain::new(~syntax_expanders)
 }
 
index ea277a8a625e728115738f892648c8f522d2762e..cde418ca991fa22d7f2afcbb0bf5ca246ff358bd 100644 (file)
@@ -8,11 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Block, Crate, NodeId, Expr_, ExprMac, Ident, mac_invoc_tt};
-use ast::{item_mac, Stmt_, StmtMac, StmtExpr, StmtSemi};
-use ast::{ILLEGAL_CTXT};
+use ast::{Block, Crate, NodeId, DeclLocal, Expr_, ExprMac, SyntaxContext};
+use ast::{Local, Ident, mac_invoc_tt};
+use ast::{item_mac, Mrk, Stmt_, StmtDecl, StmtMac, StmtExpr, StmtSemi};
+use ast::{token_tree};
 use ast;
-use ast_util::{new_rename, new_mark, resolve};
+use ast_util::{mtwt_outer_mark, new_rename, new_mark};
 use attr;
 use attr::AttrMetaMethods;
 use codemap;
@@ -23,7 +24,7 @@
 use parse;
 use parse::{parse_item_from_source_str};
 use parse::token;
-use parse::token::{ident_to_str, intern};
+use parse::token::{fresh_mark, fresh_name, ident_to_str, intern};
 use visit;
 use visit::Visitor;
 
@@ -41,8 +42,13 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
         // entry-point for all syntax extensions.
         ExprMac(ref mac) => {
             match (*mac).node {
+                // it would almost certainly be cleaner to pass the whole
+                // macro invocation in, rather than pulling it apart and
+                // marking the tts and the ctxt separately. This also goes
+                // for the other three macro invocation chunks of code
+                // in this file.
                 // Token-tree macros:
-                mac_invoc_tt(ref pth, ref tts) => {
+                mac_invoc_tt(ref pth, ref tts, ctxt) => {
                     if (pth.segments.len() > 1u) {
                         cx.span_fatal(
                             pth.span,
@@ -58,35 +64,38 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
                                 pth.span,
                                 fmt!("macro undefined: '%s'", extnamestr))
                         }
-                        Some(@SE(NormalTT(SyntaxExpanderTT{
-                            expander: exp,
-                            span: exp_sp
-                        }))) => {
+                        Some(@SE(NormalTT(expandfun, exp_span))) => {
                             cx.bt_push(ExpnInfo {
                                 call_site: s,
                                 callee: NameAndSpan {
                                     name: extnamestr,
-                                    span: exp_sp,
+                                    span: exp_span,
                                 },
                             });
-
-                            let expanded = match exp(cx, mac.span, *tts) {
-                                MRExpr(e) => e,
-                                MRAny(expr_maker,_,_) => expr_maker(),
-                                _ => {
-                                    cx.span_fatal(
-                                        pth.span,
-                                        fmt!(
-                                            "non-expr macro in expr pos: %s",
-                                            extnamestr
+                            let fm = fresh_mark();
+                            // mark before:
+                            let marked_before = mark_tts(*tts,fm);
+                            let marked_ctxt = new_mark(fm, ctxt);
+                            let expanded =
+                                match expandfun(cx, mac.span, marked_before, marked_ctxt) {
+                                    MRExpr(e) => e,
+                                    MRAny(expr_maker,_,_) => expr_maker(),
+                                    _ => {
+                                        cx.span_fatal(
+                                            pth.span,
+                                            fmt!(
+                                                "non-expr macro in expr pos: %s",
+                                                extnamestr
+                                            )
                                         )
-                                    )
-                                }
-                            };
+                                    }
+                                };
+                            // mark after:
+                            let marked_after = mark_expr(expanded,fm);
 
                             //keep going, outside-in
                             let fully_expanded =
-                                fld.fold_expr(expanded).node.clone();
+                                fld.fold_expr(marked_after).node.clone();
                             cx.bt_pop();
 
                             (fully_expanded, s)
@@ -309,7 +318,6 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv,
     ast::_mod { items: new_items, ..module_ }
 }
 
-
 // eval $e with a new exts frame:
 macro_rules! with_exts_frame (
     ($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
@@ -333,25 +341,16 @@ pub fn expand_item(extsbox: @mut SyntaxEnv,
                    fld: @ast_fold,
                    orig: @fn(@ast::item, @ast_fold) -> Option<@ast::item>)
                 -> Option<@ast::item> {
-    // need to do expansion first... it might turn out to be a module.
-    let maybe_it = match it.node {
-      ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld),
-      _ => Some(it)
-    };
-    match maybe_it {
-      Some(it) => {
-          match it.node {
-              ast::item_mod(_) | ast::item_foreign_mod(_) => {
-                  cx.mod_push(it.ident);
-                  let macro_escape = contains_macro_escape(it.attrs);
-                  let result = with_exts_frame!(extsbox,macro_escape,orig(it,fld));
-                  cx.mod_pop();
-                  result
-              }
-              _ => orig(it,fld)
-          }
-      }
-      None => None
+    match it.node {
+        ast::item_mac(*) => expand_item_mac(extsbox, cx, it, fld),
+        ast::item_mod(_) | ast::item_foreign_mod(_) => {
+            cx.mod_push(it.ident);
+            let macro_escape = contains_macro_escape(it.attrs);
+            let result = with_exts_frame!(extsbox,macro_escape,orig(it,fld));
+            cx.mod_pop();
+            result
+        },
+        _ => orig(it,fld)
     }
 }
 
@@ -366,21 +365,22 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
                        cx: @ExtCtxt, it: @ast::item,
                        fld: @ast_fold)
                     -> Option<@ast::item> {
-    let (pth, tts) = match it.node {
-        item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts), _}) => {
-            (pth, (*tts).clone())
+    let (pth, tts, ctxt) = match it.node {
+        item_mac(codemap::Spanned { node: mac_invoc_tt(ref pth, ref tts, ctxt), _}) => {
+            (pth, (*tts).clone(), ctxt)
         }
         _ => cx.span_bug(it.span, "invalid item macro invocation")
     };
 
     let extname = &pth.segments[0].identifier;
     let extnamestr = ident_to_str(extname);
+    let fm = fresh_mark();
     let expanded = match (*extsbox).find(&extname.name) {
         None => cx.span_fatal(pth.span,
                               fmt!("macro undefined: '%s!'", extnamestr)),
 
-        Some(@SE(NormalTT(ref expand))) => {
-            if it.ident != parse::token::special_idents::invalid {
+        Some(@SE(NormalTT(expander, span))) => {
+            if it.ident.name != parse::token::special_idents::invalid.name {
                 cx.span_fatal(pth.span,
                               fmt!("macro %s! expects no ident argument, \
                                     given '%s'", extnamestr,
@@ -390,13 +390,16 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
                 call_site: it.span,
                 callee: NameAndSpan {
                     name: extnamestr,
-                    span: expand.span
+                    span: span
                 }
             });
-            ((*expand).expander)(cx, it.span, tts)
+            // mark before expansion:
+            let marked_before = mark_tts(tts,fm);
+            let marked_ctxt = new_mark(fm,ctxt);
+            expander(cx, it.span, marked_before, marked_ctxt)
         }
-        Some(@SE(IdentTT(ref expand))) => {
-            if it.ident == parse::token::special_idents::invalid {
+        Some(@SE(IdentTT(expander, span))) => {
+            if it.ident.name == parse::token::special_idents::invalid.name {
                 cx.span_fatal(pth.span,
                               fmt!("macro %s! expects an ident argument",
                                    extnamestr));
@@ -405,21 +408,27 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
                 call_site: it.span,
                 callee: NameAndSpan {
                     name: extnamestr,
-                    span: expand.span
+                    span: span
                 }
             });
-            ((*expand).expander)(cx, it.span, it.ident, tts)
+            // mark before expansion:
+            let marked_tts = mark_tts(tts,fm);
+            let marked_ctxt = new_mark(fm,ctxt);
+            expander(cx, it.span, it.ident, marked_tts, marked_ctxt)
         }
         _ => cx.span_fatal(
             it.span, fmt!("%s! is not legal in item position", extnamestr))
     };
 
     let maybe_it = match expanded {
-        MRItem(it) => fld.fold_item(it),
+        MRItem(it) => mark_item(it,fm).chain(|i| {fld.fold_item(i)}),
         MRExpr(_) => cx.span_fatal(pth.span,
                                    fmt!("expr macro in item position: %s", extnamestr)),
-        MRAny(_, item_maker, _) => item_maker().chain(|i| {fld.fold_item(i)}),
+        MRAny(_, item_maker, _) => item_maker().chain(|i| {mark_item(i,fm)})
+                                      .chain(|i| {fld.fold_item(i)}),
         MRDef(ref mdef) => {
+            // yikes... no idea how to apply the mark to this. I'm afraid
+            // we're going to have to wait-and-see on this one.
             insert_macro(*extsbox,intern(mdef.name), @SE((*mdef).ext));
             None
         }
@@ -454,15 +463,17 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                    orig: @fn(&Stmt_, Span, @ast_fold)
                              -> (Option<Stmt_>, Span))
                 -> (Option<Stmt_>, Span) {
-    let (mac, pth, tts, semi) = match *s {
+    // why the copying here and not in expand_expr?
+    // looks like classic changed-in-only-one-place
+    let (mac, pth, tts, semi, ctxt) = match *s {
         StmtMac(ref mac, semi) => {
             match mac.node {
-                mac_invoc_tt(ref pth, ref tts) => {
-                    ((*mac).clone(), pth, (*tts).clone(), semi)
+                mac_invoc_tt(ref pth, ref tts, ctxt) => {
+                    ((*mac).clone(), pth, (*tts).clone(), semi, ctxt)
                 }
             }
         }
-        _ => return orig(s, sp, fld)
+        _ => return expand_non_macro_stmt(*extsbox,s,sp,fld,orig)
     };
     if (pth.segments.len() > 1u) {
         cx.span_fatal(
@@ -476,13 +487,16 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
         None =>
             cx.span_fatal(pth.span, fmt!("macro undefined: '%s'", extnamestr)),
 
-        Some(@SE(NormalTT(
-            SyntaxExpanderTT{expander: exp, span: exp_sp}))) => {
+        Some(@SE(NormalTT(expandfun, exp_span))) => {
             cx.bt_push(ExpnInfo {
                 call_site: sp,
-                callee: NameAndSpan { name: extnamestr, span: exp_sp }
+                callee: NameAndSpan { name: extnamestr, span: exp_span }
             });
-            let expanded = match exp(cx, mac.span, tts) {
+            let fm = fresh_mark();
+            // mark before expansion:
+            let marked_tts = mark_tts(tts,fm);
+            let marked_ctxt = new_mark(fm,ctxt);
+            let expanded = match expandfun(cx, mac.span, marked_tts, marked_ctxt) {
                 MRExpr(e) =>
                     @codemap::Spanned { node: StmtExpr(e, cx.next_id()),
                                     span: e.span},
@@ -491,9 +505,10 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
                     pth.span,
                     fmt!("non-stmt macro in stmt pos: %s", extnamestr))
             };
+            let marked_after = mark_stmt(expanded,fm);
 
             //keep going, outside-in
-            let fully_expanded = match fld.fold_stmt(expanded) {
+            let fully_expanded = match fld.fold_stmt(marked_after) {
                 Some(stmt) => {
                     let fully_expanded = &stmt.node;
                     cx.bt_pop();
@@ -521,6 +536,73 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
 
 }
 
+// expand a non-macro stmt. this is essentially the fallthrough for
+// expand_stmt, above.
+fn expand_non_macro_stmt (exts: SyntaxEnv,
+                          s: &Stmt_,
+                          sp: Span,
+                          fld: @ast_fold,
+                          orig: @fn(&Stmt_, Span, @ast_fold) -> (Option<Stmt_>, Span))
+    -> (Option<Stmt_>,Span) {
+    // is it a let?
+    match *s {
+        StmtDecl(@Spanned{node: DeclLocal(ref local), span: stmt_span}, node_id) => {
+            let block_info = get_block_info(exts);
+            let pending_renames = block_info.pending_renames;
+
+            // take it apart:
+            let @Local{is_mutbl:is_mutbl,
+                       ty:_,
+                       pat:pat,
+                       init:init,
+                       id:id,
+                       span:span
+                      } = *local;
+            // types can't be copied automatically because of the owned ptr in ty_tup...
+            let ty = local.ty.clone();
+            // expand the pat (it might contain exprs... #:(o)>
+            let expanded_pat = fld.fold_pat(pat);
+            // find the pat_idents in the pattern:
+            // oh dear heaven... this is going to include the enum names, as well....
+            // ... but that should be okay, as long as the new names are gensyms
+            // for the old ones.
+            let idents = @mut ~[];
+            let name_finder = new_name_finder(idents);
+            name_finder.visit_pat(expanded_pat,());
+            // generate fresh names, push them to a new pending list
+            let new_pending_renames = @mut ~[];
+            for ident in idents.iter() {
+                let new_name = fresh_name(ident);
+                new_pending_renames.push((*ident,new_name));
+            }
+            let rename_fld = renames_to_fold(new_pending_renames);
+            // rewrite the pattern using the new names (the old ones
+            // have already been applied):
+            let rewritten_pat = rename_fld.fold_pat(expanded_pat);
+            // add them to the existing pending renames:
+            for pr in new_pending_renames.iter() {pending_renames.push(*pr)}
+            // also, don't forget to expand the init:
+            let new_init_opt = init.map(|e| fld.fold_expr(*e));
+            let rewritten_local =
+                @Local{is_mutbl:is_mutbl,
+                       ty:ty,
+                       pat:rewritten_pat,
+                       init:new_init_opt,
+                       id:id,
+                       span:span};
+            (Some(StmtDecl(@Spanned{node:DeclLocal(rewritten_local),
+                                     span: stmt_span},node_id)),
+             sp)
+        },
+        _ => {
+            orig(s, sp, fld)
+        }
+    }
+}
+
+// a visitor that extracts the pat_ident paths
+// from a given thingy and puts them in a mutable
+// array (passed in to the traversal)
 #[deriving(Clone)]
 struct NewNameFinderContext {
     ident_accumulator: @mut ~[ast::Ident],
@@ -664,8 +746,133 @@ fn visit_struct_field(&mut self,
     }
 }
 
+// a visitor that extracts the paths
+// from a given thingy and puts them in a mutable
+// array (passed in to the traversal)
+#[deriving(Clone)]
+struct NewPathExprFinderContext {
+    path_accumulator: @mut ~[ast::Path],
+}
+
+// XXX : YIKES a lot of boilerplate again....
+impl Visitor<()> for NewPathExprFinderContext {
+
+    fn visit_expr(&mut self, expr: @ast::Expr, _: ()) {
+        match *expr {
+            ast::Expr{id:_,span:_,node:ast::ExprPath(ref p)} => {
+                self.path_accumulator.push(p.clone());
+                // not calling visit_path, should be fine.
+            }
+            _ => visit::walk_expr(self,expr,())
+        }
+    }
+
+
+    // XXX: Methods below can become default methods.
+
+    fn visit_pat(&mut self, pattern: @ast::Pat, _: ()) {
+        visit::walk_pat(self,pattern,())
+    }
+
+    fn visit_mod(&mut self, module: &ast::_mod, _: Span, _: NodeId, _: ()) {
+        visit::walk_mod(self, module, ())
+    }
+
+    fn visit_view_item(&mut self, view_item: &ast::view_item, _: ()) {
+        visit::walk_view_item(self, view_item, ())
+    }
+
+    fn visit_item(&mut self, item: @ast::item, _: ()) {
+        visit::walk_item(self, item, ())
+    }
+
+    fn visit_foreign_item(&mut self,
+                          foreign_item: @ast::foreign_item,
+                          _: ()) {
+        visit::walk_foreign_item(self, foreign_item, ())
+    }
+
+    fn visit_local(&mut self, local: @ast::Local, _: ()) {
+        visit::walk_local(self, local, ())
+    }
+
+    fn visit_block(&mut self, block: &ast::Block, _: ()) {
+        visit::walk_block(self, block, ())
+    }
+
+    fn visit_stmt(&mut self, stmt: @ast::Stmt, _: ()) {
+        visit::walk_stmt(self, stmt, ())
+    }
+
+    fn visit_arm(&mut self, arm: &ast::Arm, _: ()) {
+        visit::walk_arm(self, arm, ())
+    }
+
+    fn visit_decl(&mut self, decl: @ast::Decl, _: ()) {
+        visit::walk_decl(self, decl, ())
+    }
+
+    fn visit_expr_post(&mut self, _: @ast::Expr, _: ()) {
+        // Empty!
+    }
+
+    fn visit_ty(&mut self, typ: &ast::Ty, _: ()) {
+        visit::walk_ty(self, typ, ())
+    }
+
+    fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
+        visit::walk_generics(self, generics, ())
+    }
+
+    fn visit_fn(&mut self,
+                function_kind: &visit::fn_kind,
+                function_declaration: &ast::fn_decl,
+                block: &ast::Block,
+                span: Span,
+                node_id: NodeId,
+                _: ()) {
+        visit::walk_fn(self,
+                        function_kind,
+                        function_declaration,
+                        block,
+                        span,
+                        node_id,
+                        ())
+    }
+
+    fn visit_ty_method(&mut self, ty_method: &ast::TypeMethod, _: ()) {
+        visit::walk_ty_method(self, ty_method, ())
+    }
+
+    fn visit_trait_method(&mut self,
+                          trait_method: &ast::trait_method,
+                          _: ()) {
+        visit::walk_trait_method(self, trait_method, ())
+    }
+
+    fn visit_struct_def(&mut self,
+                        struct_def: @ast::struct_def,
+                        ident: Ident,
+                        generics: &ast::Generics,
+                        node_id: NodeId,
+                        _: ()) {
+        visit::walk_struct_def(self,
+                                struct_def,
+                                ident,
+                                generics,
+                                node_id,
+                                ())
+    }
+
+    fn visit_struct_field(&mut self,
+                          struct_field: @ast::struct_field,
+                          _: ()) {
+        visit::walk_struct_field(self, struct_field, ())
+    }
+}
+
 // return a visitor that extracts the pat_ident paths
-// from a given pattern and puts them in a mutable
+// from a given thingy and puts them in a mutable
 // array (passed in to the traversal)
 pub fn new_name_finder(idents: @mut ~[ast::Ident]) -> @mut Visitor<()> {
     let context = @mut NewNameFinderContext {
@@ -674,16 +881,60 @@ pub fn new_name_finder(idents: @mut ~[ast::Ident]) -> @mut Visitor<()> {
     context as @mut Visitor<()>
 }
 
+// return a visitor that extracts the paths
+// from a given pattern and puts them in a mutable
+// array (passed in to the traversal)
+pub fn new_path_finder(paths: @mut ~[ast::Path]) -> @mut Visitor<()> {
+    let context = @mut NewPathExprFinderContext {
+        path_accumulator: paths,
+    };
+    context as @mut Visitor<()>
+}
+
+// expand a block. pushes a new exts_frame, then calls expand_block_elts
 pub fn expand_block(extsbox: @mut SyntaxEnv,
                     _cx: @ExtCtxt,
                     blk: &Block,
                     fld: @ast_fold,
-                    orig: @fn(&Block, @ast_fold) -> Block)
+                    _orig: @fn(&Block, @ast_fold) -> Block)
                  -> Block {
     // see note below about treatment of exts table
-    with_exts_frame!(extsbox,false,orig(blk,fld))
+    with_exts_frame!(extsbox,false,
+                     expand_block_elts(*extsbox, blk, fld))
+}
+
+// expand the elements of a block.
+pub fn expand_block_elts(exts: SyntaxEnv, b: &Block, fld: @ast_fold) -> Block {
+    let block_info = get_block_info(exts);
+    let pending_renames = block_info.pending_renames;
+    let rename_fld = renames_to_fold(pending_renames);
+    let new_view_items = b.view_items.map(|x| fld.fold_view_item(x));
+    let mut new_stmts = ~[];
+    for x in b.stmts.iter() {
+        match fld.fold_stmt(mustbesome(rename_fld.fold_stmt(*x))) {
+            Some(s) => new_stmts.push(s),
+            None => ()
+        }
+    }
+    let new_expr = b.expr.map(|x| fld.fold_expr(rename_fld.fold_expr(*x)));
+    Block{
+        view_items: new_view_items,
+        stmts: new_stmts,
+        expr: new_expr,
+        id: fld.new_id(b.id),
+        rules: b.rules,
+        span: b.span,
+    }
 }
 
+// rename_fold should never return "None".
+// (basically, just .get() with a better message...)
+fn mustbesome<T>(val : Option<T>) -> T {
+    match val {
+        Some(v) => v,
+        None => fail!("rename_fold returned None")
+    }
+}
 
 // get the (innermost) BlockInfo from an exts stack
 fn get_block_info(exts : SyntaxEnv) -> BlockInfo {
@@ -694,43 +945,14 @@ fn get_block_info(exts : SyntaxEnv) -> BlockInfo {
     }
 }
 
-
-// given a mutable list of renames, return a tree-folder that applies those
-// renames.
-fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @ast_fold {
-    let afp = default_ast_fold();
-    let f_pre = @AstFoldFns {
-        fold_ident: |id,_| {
-            // the individual elements are memoized... it would
-            // also be possible to memoize on the whole list at once.
-            let new_ctxt = renames.iter().fold(id.ctxt,|ctxt,&(from,to)| {
-                new_rename(from,to,ctxt)
-            });
-            ast::Ident{name:id.name,ctxt:new_ctxt}
-        },
-        .. *afp
-    };
-    make_fold(f_pre)
-}
-
-// perform a bunch of renames
-fn apply_pending_renames(folder : @ast_fold, stmt : ast::Stmt) -> @ast::Stmt {
-    match folder.fold_stmt(&stmt) {
-        Some(s) => s,
-        None => fail!(fmt!("renaming of stmt produced None"))
-    }
-}
-
-
-
 pub fn new_span(cx: @ExtCtxt, sp: Span) -> Span {
     /* this discards information in the case of macro-defining macros */
     return Span {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
 }
 
 // FIXME (#2247): this is a moderately bad kludge to inject some macros into
-// the default compilation environment. It would be much nicer to use
-// a mechanism like syntax_quote to ensure hygiene.
+// the default compilation environment in that it injects strings, rather than
+// syntax elements.
 
 pub fn std_macros() -> @str {
     return
@@ -1179,62 +1401,165 @@ pub fn expand_crate(parse_sess: @mut parse::ParseSess,
     return ret;
 }
 
-// given a function from idents to idents, produce
-// an ast_fold that applies that function:
-pub fn fun_to_ident_folder(f: @fn(ast::Ident)->ast::Ident) -> @ast_fold{
-    let afp = default_ast_fold();
-    let f_pre = @AstFoldFns{
-        fold_ident : |id, _| f(id),
-        .. *afp
-    };
-    make_fold(f_pre)
+// HYGIENIC CONTEXT EXTENSION:
+// all of these functions are for walking over
+// ASTs and making some change to the context of every
+// element that has one. a CtxtFn is a trait-ified
+// version of a closure in (SyntaxContext -> SyntaxContext).
+// the ones defined here include:
+// Renamer - add a rename to a context
+// MultiRenamer - add a set of renames to a context
+// Marker - add a mark to a context
+// Repainter - replace a context (maybe Replacer would be a better name?)
+
+// a function in SyntaxContext -> SyntaxContext
+pub trait CtxtFn{
+    fn f(&self, ast::SyntaxContext) -> ast::SyntaxContext;
 }
 
-// update the ctxts in a path to get a rename node
-pub fn new_ident_renamer(from: ast::Ident,
-                      to: ast::Name) ->
-    @fn(ast::Ident)->ast::Ident {
-    |id : ast::Ident|
-    ast::Ident{
-        name: id.name,
-        ctxt: new_rename(from,to,id.ctxt)
+// a renamer adds a rename to the syntax context
+pub struct Renamer {
+    from : ast::Ident,
+    to : ast::Name
+}
+
+impl CtxtFn for Renamer {
+    fn f(&self, ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
+        new_rename(self.from,self.to,ctxt)
+    }
+}
+
+// a renamer that performs a whole bunch of renames
+pub struct MultiRenamer {
+    renames : @mut ~[(ast::Ident,ast::Name)]
+}
+
+impl CtxtFn for MultiRenamer {
+    fn f(&self, starting_ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
+        // the individual elements are memoized... it would
+        // also be possible to memoize on the whole list at once.
+        self.renames.iter().fold(starting_ctxt,|ctxt,&(from,to)| {
+            new_rename(from,to,ctxt)
+        })
+    }
+}
+
+// a marker adds the given mark to the syntax context
+pub struct Marker { mark : Mrk }
+
+impl CtxtFn for Marker {
+    fn f(&self, ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
+        new_mark(self.mark,ctxt)
     }
 }
 
+// a repainter just replaces the given context with the one it's closed over
+pub struct Repainter { ctxt : SyntaxContext }
 
-// update the ctxts in a path to get a mark node
-pub fn new_ident_marker(mark: uint) ->
-    @fn(ast::Ident)->ast::Ident {
-    |id : ast::Ident|
-    ast::Ident{
-        name: id.name,
-        ctxt: new_mark(mark,id.ctxt)
+impl CtxtFn for Repainter {
+    fn f(&self, _ctxt : ast::SyntaxContext) -> ast::SyntaxContext {
+        self.ctxt
     }
 }
 
-// perform resolution (in the MTWT sense) on all of the
-// idents in the tree. This is the final step in expansion.
-pub fn new_ident_resolver() ->
-    @fn(ast::Ident)->ast::Ident {
-    |id : ast::Ident|
-    ast::Ident {
-        name : resolve(id),
-        ctxt : ILLEGAL_CTXT
+// given a function from ctxts to ctxts, produce
+// an ast_fold that applies that function to all ctxts:
+pub fn fun_to_ctxt_folder<T : 'static + CtxtFn>(cf: @T) -> @AstFoldFns {
+    let afp = default_ast_fold();
+    let fi : @fn(ast::Ident, @ast_fold) -> ast::Ident =
+        |ast::Ident{name, ctxt}, _| {
+        ast::Ident{name:name,ctxt:cf.f(ctxt)}
+    };
+    let fm : @fn(&ast::mac_, Span, @ast_fold) -> (ast::mac_,Span) =
+        |m, sp, fld| {
+        match *m {
+            mac_invoc_tt(ref path, ref tts, ctxt) =>
+            (mac_invoc_tt(fld.fold_path(path),
+                         fold_tts(*tts,fld),
+                         cf.f(ctxt)),
+            sp)
+        }
+
+    };
+    @AstFoldFns{
+        fold_ident : fi,
+        fold_mac : fm,
+        .. *afp
     }
 }
 
 
+
+// given a mutable list of renames, return a tree-folder that applies those
+// renames.
+// FIXME #4536: currently pub to allow testing
+pub fn renames_to_fold(renames : @mut ~[(ast::Ident,ast::Name)]) -> @AstFoldFns {
+    fun_to_ctxt_folder(@MultiRenamer{renames : renames})
+}
+
+// just a convenience:
+pub fn new_mark_folder(m : Mrk) -> @AstFoldFns {
+    fun_to_ctxt_folder(@Marker{mark:m})
+}
+
+pub fn new_rename_folder(from : ast::Ident, to : ast::Name) -> @AstFoldFns {
+    fun_to_ctxt_folder(@Renamer{from:from,to:to})
+}
+
+// apply a given mark to the given token trees. Used prior to expansion of a macro.
+fn mark_tts(tts : &[token_tree], m : Mrk) -> ~[token_tree] {
+    fold_tts(tts,new_mark_folder(m) as @ast_fold)
+}
+
+// apply a given mark to the given expr. Used following the expansion of a macro.
+fn mark_expr(expr : @ast::Expr, m : Mrk) -> @ast::Expr {
+    new_mark_folder(m).fold_expr(expr)
+}
+
+// apply a given mark to the given stmt. Used following the expansion of a macro.
+fn mark_stmt(expr : &ast::Stmt, m : Mrk) -> @ast::Stmt {
+    new_mark_folder(m).fold_stmt(expr).unwrap()
+}
+
+// apply a given mark to the given item. Used following the expansion of a macro.
+fn mark_item(expr : @ast::item, m : Mrk) -> Option<@ast::item> {
+    new_mark_folder(m).fold_item(expr)
+}
+
+// replace all contexts in a given expr with the given mark. Used
+// for capturing macros
+pub fn replace_ctxts(expr : @ast::Expr, ctxt : SyntaxContext) -> @ast::Expr {
+    fun_to_ctxt_folder(@Repainter{ctxt:ctxt}).fold_expr(expr)
+}
+
+// take the mark from the given ctxt (that has a mark at the outside),
+// and apply it to everything in the token trees, thereby cancelling
+// that mark.
+pub fn mtwt_cancel_outer_mark(tts: &[ast::token_tree], ctxt: ast::SyntaxContext)
+    -> ~[ast::token_tree] {
+    let outer_mark = mtwt_outer_mark(ctxt);
+    mark_tts(tts,outer_mark)
+}
+
+
 #[cfg(test)]
 mod test {
     use super::*;
     use ast;
     use ast::{Attribute_, AttrOuter, MetaWord, EMPTY_CTXT};
+    use ast_util::{get_sctable, mtwt_marksof, mtwt_resolve, new_rename};
+    use ast_util;
     use codemap;
     use codemap::Spanned;
+    use fold;
     use parse;
-    use parse::token::{intern, get_ident_interner};
+    use parse::token::{fresh_mark, gensym, intern, get_ident_interner, ident_to_str};
+    use parse::token;
     use print::pprust;
-    use util::parser_testing::{string_to_item, string_to_pat, strs_to_idents};
+    use std;
+    use util::parser_testing::{string_to_crate, string_to_crate_and_sess};
+    use util::parser_testing::{string_to_pat, string_to_tts, strs_to_idents};
+    use visit;
 
     // make sure that fail! is present
     #[test] fn fail_exists_test () {
@@ -1332,28 +1657,251 @@ fn make_dummy_attr(s: @str) -> ast::Attribute {
         }
     }
 
+    #[test] fn cancel_outer_mark_test(){
+        let invalid_name = token::special_idents::invalid.name;
+        let ident_str = @"x";
+        let tts = string_to_tts(ident_str);
+        let fm = fresh_mark();
+        let marked_once = fold::fold_tts(tts,new_mark_folder(fm) as @fold::ast_fold);
+        assert_eq!(marked_once.len(),1);
+        let marked_once_ctxt =
+            match marked_once[0] {
+                ast::tt_tok(_,token::IDENT(id,_)) => id.ctxt,
+                _ => fail!(fmt!("unexpected shape for marked tts: %?",marked_once[0]))
+            };
+        assert_eq!(mtwt_marksof(marked_once_ctxt,invalid_name),~[fm]);
+        let remarked = mtwt_cancel_outer_mark(marked_once,marked_once_ctxt);
+        assert_eq!(remarked.len(),1);
+        match remarked[0] {
+            ast::tt_tok(_,token::IDENT(id,_)) =>
+            assert_eq!(mtwt_marksof(id.ctxt,invalid_name),~[]),
+            _ => fail!(fmt!("unexpected shape for marked tts: %?",remarked[0]))
+        }
+    }
+
     #[test]
     fn renaming () {
-        let maybe_item_ast = string_to_item(@"fn a() -> int { let b = 13; b }");
-        let item_ast = match maybe_item_ast {
-            Some(x) => x,
-            None => fail!("test case fail")
-        };
+        let item_ast = string_to_crate(@"fn f() -> int { a }");
         let a_name = intern("a");
-        let a2_name = intern("a2");
-        let renamer = new_ident_renamer(ast::Ident{name:a_name,ctxt:EMPTY_CTXT},
+        let a2_name = gensym("a2");
+        let renamer = new_rename_folder(ast::Ident{name:a_name,ctxt:EMPTY_CTXT},
                                         a2_name);
-        let renamed_ast = fun_to_ident_folder(renamer).fold_item(item_ast).unwrap();
-        let resolver = new_ident_resolver();
-        let resolved_ast = fun_to_ident_folder(resolver).fold_item(renamed_ast).unwrap();
-        let resolved_as_str = pprust::item_to_str(resolved_ast,
-                                                  get_ident_interner());
-        assert_eq!(resolved_as_str,~"fn a2() -> int { let b = 13; b }");
+        let renamed_ast = renamer.fold_crate(item_ast);
+        let varrefs = @mut ~[];
+        visit::walk_crate(&mut new_path_finder(varrefs), &renamed_ast, ());
+        match varrefs {
+            @[Path{segments:[ref seg],_}] => assert_eq!(mtwt_resolve(seg.identifier),a2_name),
+            _ => assert_eq!(0,1)
+        }
+
+        // try a double-rename, with pending_renames.
+        let a3_name = gensym("a3");
+        // a context that renames from ("a",empty) to "a2" :
+        let ctxt2 = new_rename(ast::Ident::new(a_name),a2_name,EMPTY_CTXT);
+        let pending_renames = @mut ~[(ast::Ident::new(a_name),a2_name),
+                                     (ast::Ident{name:a_name,ctxt:ctxt2},a3_name)];
+        let double_renamed = renames_to_fold(pending_renames).fold_crate(item_ast);
+        let varrefs = @mut ~[];
+        visit::walk_crate(&mut new_path_finder(varrefs), &double_renamed, ());
+        match varrefs {
+            @[Path{segments:[ref seg],_}] => assert_eq!(mtwt_resolve(seg.identifier),a3_name),
+            _ => assert_eq!(0,1)
+        }
+    }
 
+    fn fake_print_crate(crate: @ast::Crate) {
+        let s = pprust::rust_printer(std::io::stderr(),get_ident_interner());
+        pprust::print_crate_(s, crate);
+    }
 
+    fn expand_crate_str(crate_str: @str) -> @ast::Crate {
+        let (crate_ast,ps) = string_to_crate_and_sess(crate_str);
+        // the cfg argument actually does matter, here...
+        expand_crate(ps,~[],crate_ast)
     }
 
-    // sigh... it looks like I have two different renaming mechanisms, now...
+    //fn expand_and_resolve(crate_str: @str) -> ast::crate {
+        //let expanded_ast = expand_crate_str(crate_str);
+        // std::io::println(fmt!("expanded: %?\n",expanded_ast));
+        //mtwt_resolve_crate(expanded_ast)
+    //}
+    //fn expand_and_resolve_and_pretty_print (crate_str : @str) -> ~str {
+        //let resolved_ast = expand_and_resolve(crate_str);
+        //pprust::to_str(&resolved_ast,fake_print_crate,get_ident_interner())
+    //}
+
+    #[test] fn macro_tokens_should_match(){
+        expand_crate_str(@"macro_rules! m((a)=>(13)) fn main(){m!(a);}");
+    }
+
+    // renaming tests expand a crate and then check that the bindings match
+    // the right varrefs. The specification of the test case includes the
+    // text of the crate, and also an array of arrays.  Each element in the
+    // outer array corresponds to a binding in the traversal of the AST
+    // induced by visit.  Each of these arrays contains a list of indexes,
+    // interpreted as the varrefs in the varref traversal that this binding
+    // should match.  So, for instance, in a program with two bindings and
+    // three varrefs, the array ~[~[1,2],~[0]] would indicate that the first
+    // binding should match the second two varrefs, and the second binding
+    // should match the first varref.
+    //
+    // The comparisons are done post-mtwt-resolve, so we're comparing renamed
+    // names; differences in marks don't matter any more.
+    //
+    // 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 () {
+        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]], false),
+                // both x's should be renamed (how is this causing a bug?)
+                ("fn main () {let x : int = 13;x;}",
+                 ~[~[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]], 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]], 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]], false),
+                // FIXME #8062: this test exposes a *potential* bug; our system does
+                // not behave exactly like MTWT, but I haven't thought of a way that
+                // this could cause a bug in Rust, yet.
+                // ("fn main() {let hrcoo = 19; macro_rules! getx(()=>(hrcoo)); 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
+                // (just g) along the other, so the result of the whole thing should
+                // be "let z_123 = 3; z_123"
+                //"macro_rules! g (($x:ident) =>
+                //   ({macro_rules! f(($y:ident)=>({let $y=3;$x}));f!($x)}))
+                //   fn a(){g!(z)}"
+                // create a really evil test case where a $x appears inside a binding of $x
+                // but *shouldnt* bind because it was inserted by a different macro....
+            ];
+        for (idx,s) in tests.iter().enumerate() {
+            run_renaming_test(s,idx);
+        }
+    }
+
+    // run one of the renaming tests
+    fn run_renaming_test(t : &renaming_test, test_idx: uint) {
+        let invalid_name = token::special_idents::invalid.name;
+        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:
+        let bindings = @mut ~[];
+        visit::walk_crate(&mut new_name_finder(bindings),cr,());
+        // find the varrefs:
+        let varrefs = @mut ~[];
+        visit::walk_crate(&mut new_path_finder(varrefs),cr,());
+        // 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[binding_idx]);
+            let binding_marks = mtwt_marksof(bindings[binding_idx].ctxt,invalid_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=? 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,
+                                                    invalid_name);
+                    if (!(varref_name==binding_name)){
+                        std::io::println("uh oh, should match but doesn't:");
+                        std::io::println(fmt!("varref: %?",varref));
+                        std::io::println(fmt!("binding: %?", bindings[binding_idx]));
+                        ast_util::display_sctable(get_sctable());
+                    }
+                    assert_eq!(varref_name,binding_name);
+                    if (bound_ident_check) {
+                        // we're checking bound-identifier=?, and the marks
+                        // should be the same, too:
+                        assert_eq!(varref_marks,binding_marks.clone());
+                    }
+                } else {
+                    let fail = (varref.segments.len() == 1)
+                        && (mtwt_resolve(varref.segments[0].identifier) == binding_name);
+                    // temp debugging:
+                    if (fail) {
+                        println!("failure on test {}",test_idx);
+                        println!("text of test case: \"{}\"", teststr);
+                        println!("");
+                        println!("uh oh, matches but shouldn't:");
+                        std::io::println(fmt!("varref: %?",varref));
+                        // good lord, you can't make a path with 0 segments, can you?
+                        println!("varref's first segment's uint: {}, and string: \"{}\"",
+                                 varref.segments[0].identifier.name,
+                                 ident_to_str(&varref.segments[0].identifier));
+                        std::io::println(fmt!("binding: %?", bindings[binding_idx]));
+                        ast_util::display_sctable(get_sctable());
+                    }
+                    assert!(!fail);
+                }
+            }
+        }
+    }
+
+    #[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(){
@@ -1363,4 +1911,5 @@ fn pat_idents(){
         pat_idents.visit_pat(pat, ());
         assert_eq!(idents, @mut strs_to_idents(~["a","c","b","d"]));
     }
+
 }
index 4e8b7467c5c00c84a61bb3eecdbb37de226167c5..6527b083cc1b6f35bcd88b4989eff7a9ed43595d 100644 (file)
@@ -293,45 +293,51 @@ pub fn expand_quote_tokens(cx: @ExtCtxt,
                            sp: Span,
                            tts: &[ast::token_tree]) -> base::MacResult {
     let (cx_expr, expr) = expand_tts(cx, sp, tts);
-    base::MRExpr(expand_wrapper(cx, sp, cx_expr, expr))
+    let expanded = expand_wrapper(cx, sp, cx_expr, expr);
+    base::MRExpr(expanded)
 }
 
 pub fn expand_quote_expr(cx: @ExtCtxt,
                          sp: Span,
                          tts: &[ast::token_tree]) -> base::MacResult {
-    base::MRExpr(expand_parse_call(cx, sp, "parse_expr", ~[], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_expr", ~[], tts);
+    base::MRExpr(expanded)
 }
 
 pub fn expand_quote_item(cx: @ExtCtxt,
                          sp: Span,
                          tts: &[ast::token_tree]) -> base::MacResult {
     let e_attrs = cx.expr_vec_uniq(sp, ~[]);
-    base::MRExpr(expand_parse_call(cx, sp, "parse_item",
-                                    ~[e_attrs], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_item",
+                                    ~[e_attrs], tts);
+    base::MRExpr(expanded)
 }
 
 pub fn expand_quote_pat(cx: @ExtCtxt,
                         sp: Span,
                         tts: &[ast::token_tree]) -> base::MacResult {
     let e_refutable = cx.expr_lit(sp, ast::lit_bool(true));
-    base::MRExpr(expand_parse_call(cx, sp, "parse_pat",
-                                    ~[e_refutable], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_pat",
+                                    ~[e_refutable], tts);
+    base::MRExpr(expanded)
 }
 
 pub fn expand_quote_ty(cx: @ExtCtxt,
                        sp: Span,
                        tts: &[ast::token_tree]) -> base::MacResult {
     let e_param_colons = cx.expr_lit(sp, ast::lit_bool(false));
-    base::MRExpr(expand_parse_call(cx, sp, "parse_ty",
-                                    ~[e_param_colons], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_ty",
+                                     ~[e_param_colons], tts);
+    base::MRExpr(expanded)
 }
 
 pub fn expand_quote_stmt(cx: @ExtCtxt,
                          sp: Span,
                          tts: &[ast::token_tree]) -> base::MacResult {
     let e_attrs = cx.expr_vec_uniq(sp, ~[]);
-    base::MRExpr(expand_parse_call(cx, sp, "parse_stmt",
-                                    ~[e_attrs], tts))
+    let expanded = expand_parse_call(cx, sp, "parse_stmt",
+                                    ~[e_attrs], tts);
+    base::MRExpr(expanded)
 }
 
 fn ids_ext(strs: ~[~str]) -> ~[ast::Ident] {
index 7a9e916421c0f74e84e48badc94b0412eb36f5dc..aa4183837e3b38d4554fe1b16931f8bdb72e9a7a 100644 (file)
@@ -234,6 +234,15 @@ pub fn parse_or_else(
     }
 }
 
+// perform a token equality check, ignoring syntax context (that is, an unhygienic comparison)
+pub fn token_name_eq(t1 : &Token, t2 : &Token) -> bool {
+    match (t1,t2) {
+        (&token::IDENT(id1,_),&token::IDENT(id2,_)) =>
+        id1.name == id2.name,
+        _ => *t1 == *t2
+    }
+}
+
 pub fn parse(
     sess: @mut ParseSess,
     cfg: ast::CrateConfig,
@@ -297,7 +306,10 @@ pub fn parse(
                     // the *_t vars are workarounds for the lack of unary move
                     match ei.sep {
                       Some(ref t) if idx == len => { // we need a separator
-                        if tok == (*t) { //pass the separator
+                        // i'm conflicted about whether this should be hygienic....
+                        // though in this case, if the separators are never legal
+                        // idents, it shouldn't matter.
+                        if token_name_eq(&tok, t) { //pass the separator
                             let mut ei_t = ei.clone();
                             ei_t.idx += 1;
                             next_eis.push(ei_t);
@@ -343,7 +355,8 @@ pub fn parse(
                   match_nonterminal(_,_,_) => { bb_eis.push(ei) }
                   match_tok(ref t) => {
                     let mut ei_t = ei.clone();
-                    if (*t) == tok {
+                    //if (token_name_eq(t,&tok)) {
+                    if (token::mtwt_token_eq(t,&tok)) {
                         ei_t.idx += 1;
                         next_eis.push(ei_t);
                     }
@@ -353,7 +366,7 @@ pub fn parse(
         }
 
         /* error messages here could be improved with links to orig. rules */
-        if tok == EOF {
+        if token_name_eq(&tok, &EOF) {
             if eof_eis.len() == 1u {
                 let mut v = ~[];
                 for dv in eof_eis[0u].matches.mut_iter() {
index 732ae2ccb9608bb100be0a1c94a877691c42c7e4..74de8eaa09e0676ceb8d3613f293c7ded9eeb78c 100644 (file)
@@ -14,6 +14,7 @@
 use codemap::{Span, Spanned, dummy_sp};
 use ext::base::{ExtCtxt, MacResult, MRAny, MRDef, MacroDef, NormalTT};
 use ext::base;
+use ext::expand;
 use ext::tt::macro_parser::{error};
 use ext::tt::macro_parser::{named_match, matched_seq, matched_nonterminal};
 use ext::tt::macro_parser::{parse, parse_or_else, success, failure};
 use parse::token::{FAT_ARROW, SEMI, nt_matchers, nt_tt};
 use print;
 
+// this procedure performs the expansion of the
+// macro_rules! macro. It parses the RHS and adds
+// an extension to the current context.
 pub fn add_new_extension(cx: @ExtCtxt,
                          sp: Span,
                          name: Ident,
-                         arg: ~[ast::token_tree])
+                         arg: ~[ast::token_tree],
+                         stx_ctxt: ast::SyntaxContext)
                       -> base::MacResult {
+    let arg = expand::mtwt_cancel_outer_mark(arg,stx_ctxt);
+    // Wrap a matcher_ in a spanned to produce a matcher.
     // these spans won't matter, anyways
     fn ms(m: matcher_) -> matcher {
         Spanned {
@@ -39,6 +46,7 @@ fn ms(m: matcher_) -> matcher {
     let lhs_nm =  gensym_ident("lhs");
     let rhs_nm =  gensym_ident("rhs");
 
+    // The pattern that macro_rules matches.
     // The grammar for macro_rules! is:
     // $( $lhs:mtcs => $rhs:tt );+
     // ...quasiquoting this would be nice.
@@ -144,11 +152,11 @@ fn generic_extension(cx: @ExtCtxt, sp: Span, name: Ident,
         cx.span_fatal(best_fail_spot, best_fail_msg);
     }
 
-    let exp: @fn(@ExtCtxt, Span, &[ast::token_tree]) -> MacResult =
-        |cx, sp, arg| generic_extension(cx, sp, name, arg, *lhses, *rhses);
+    let exp: @fn(@ExtCtxt, Span, &[ast::token_tree], ctxt: ast::SyntaxContext) -> MacResult =
+        |cx, sp, arg, _ctxt| generic_extension(cx, sp, name, arg, *lhses, *rhses);
 
     return MRDef(MacroDef{
         name: ident_to_str(&name),
-        ext: NormalTT(base::SyntaxExpanderTT{expander: exp, span: Some(sp)})
+        ext: NormalTT(exp, Some(sp))
     });
 }
index 7aa0f3abe87cd3bb39ff588b5b0f9349cc8d720d..aad992706fd01271e86209eb6f4a77962d3b20f1 100644 (file)
 use parse::token;
 use opt_vec::OptVec;
 
+// this file defines an ast_fold trait for objects that can perform
+// a "fold" on Rust ASTs. It also contains a structure that implements
+// that trait, and a "default_fold" whose fields contain closures
+// that perform "default traversals", visiting all of the sub-elements
+// and re-assembling the result. The "fun_to_ident_folder" in the
+// test module provides a simple example of creating a very simple
+// fold that only looks at identifiers.
+
 pub trait ast_fold {
     fn fold_crate(@self, &Crate) -> Crate;
     fn fold_view_item(@self, &view_item) -> view_item;
@@ -35,6 +43,7 @@ pub trait ast_fold {
     fn fold_ident(@self, Ident) -> Ident;
     fn fold_path(@self, &Path) -> Path;
     fn fold_local(@self, @Local) -> @Local;
+    fn fold_mac(@self, &mac) -> mac;
     fn map_exprs(@self, @fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr];
     fn new_id(@self, NodeId) -> NodeId;
     fn new_span(@self, Span) -> Span;
@@ -64,6 +73,7 @@ pub struct AstFoldFns {
     fold_ident: @fn(Ident, @ast_fold) -> Ident,
     fold_path: @fn(&Path, @ast_fold) -> Path,
     fold_local: @fn(@Local, @ast_fold) -> @Local,
+    fold_mac: @fn(&mac_, Span, @ast_fold) -> (mac_, Span),
     map_exprs: @fn(@fn(@Expr) -> @Expr, &[@Expr]) -> ~[@Expr],
     new_id: @fn(NodeId) -> NodeId,
     new_span: @fn(Span) -> Span
@@ -112,41 +122,31 @@ fn fold_arg_(a: arg, fld: @ast_fold) -> arg {
     }
 }
 
-//used in noop_fold_expr, and possibly elsewhere in the future
-fn fold_mac_(m: &mac, fld: @ast_fold) -> mac {
-    Spanned {
-        node: match m.node {
-            mac_invoc_tt(ref p,ref tts) =>
-            mac_invoc_tt(fld.fold_path(p),
-                         fold_tts(*tts,fld))
-        },
-        span: fld.new_span(m.span)
-    }
-}
-
-fn fold_tts(tts : &[token_tree], fld: @ast_fold) -> ~[token_tree] {
+// build a new vector of tts by appling the ast_fold's fold_ident to
+// all of the identifiers in the token trees.
+pub fn fold_tts(tts : &[token_tree], f : @ast_fold) -> ~[token_tree] {
     do tts.map |tt| {
         match *tt {
             tt_tok(span, ref tok) =>
-            tt_tok(span,maybe_fold_ident(tok,fld)),
+            tt_tok(span,maybe_fold_ident(tok,f)),
             tt_delim(ref tts) =>
-            tt_delim(@mut fold_tts(**tts, fld)),
+            tt_delim(@mut fold_tts(**tts, f)),
             tt_seq(span, ref pattern, ref sep, is_optional) =>
             tt_seq(span,
-                   @mut fold_tts(**pattern, fld),
-                   sep.map(|tok|maybe_fold_ident(tok,fld)),
+                   @mut fold_tts(**pattern, f),
+                   sep.map(|tok|maybe_fold_ident(tok,f)),
                    is_optional),
             tt_nonterminal(sp,ref ident) =>
-            tt_nonterminal(sp,fld.fold_ident(*ident))
+            tt_nonterminal(sp,f.fold_ident(*ident))
         }
     }
 }
 
 // apply ident folder if it's an ident, otherwise leave it alone
-fn maybe_fold_ident(t: &token::Token, fld: @ast_fold) -> token::Token {
+fn maybe_fold_ident(t : &token::Token, f: @ast_fold) -> token::Token {
     match *t {
         token::IDENT(id,followed_by_colons) =>
-        token::IDENT(fld.fold_ident(id),followed_by_colons),
+        token::IDENT(f.fold_ident(id),followed_by_colons),
         _ => (*t).clone()
     }
 }
@@ -209,6 +209,7 @@ pub fn noop_fold_crate(c: &Crate, fld: @ast_fold) -> Crate {
 }
 
 fn noop_fold_view_item(vi: &view_item_, _fld: @ast_fold) -> view_item_ {
+    // FIXME #7654: doesn't iterate over idents in a view_item_use
     return /* FIXME (#2543) */ (*vi).clone();
 }
 
@@ -323,11 +324,7 @@ pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ {
             )
         }
         item_mac(ref m) => {
-            // FIXME #2888: we might actually want to do something here.
-            // ... okay, we're doing something. It would probably be nicer
-            // to add something to the ast_fold trait, but I'll defer
-            // that work.
-            item_mac(fold_mac_(m,fld))
+            item_mac(fld.fold_mac(m))
         }
     }
 }
@@ -396,7 +393,6 @@ pub fn noop_fold_block(b: &Block, fld: @ast_fold) -> Block {
 }
 
 fn noop_fold_stmt(s: &Stmt_, fld: @ast_fold) -> Option<Stmt_> {
-    let fold_mac = |x| fold_mac_(x, fld);
     match *s {
         StmtDecl(d, nid) => {
             match fld.fold_decl(d) {
@@ -410,7 +406,7 @@ fn noop_fold_stmt(s: &Stmt_, fld: @ast_fold) -> Option<Stmt_> {
         StmtSemi(e, nid) => {
             Some(StmtSemi(fld.fold_expr(e), fld.new_id(nid)))
         }
-        StmtMac(ref mac, semi) => Some(StmtMac(fold_mac(mac), semi))
+        StmtMac(ref mac, semi) => Some(StmtMac(fld.fold_mac(mac), semi))
     }
 }
 
@@ -478,6 +474,12 @@ fn noop_fold_decl(d: &Decl_, fld: @ast_fold) -> Option<Decl_> {
     }
 }
 
+// lift a function in ast-thingy X fold -> ast-thingy to a function
+// in (ast-thingy X span X fold) -> (ast-thingy X span). Basically,
+// carries the span around.
+// It seems strange to me that the call to new_fold doesn't happen
+// here but instead in the impl down below.... probably just an
+// accident?
 pub fn wrap<T>(f: @fn(&T, @ast_fold) -> T)
             -> @fn(&T, Span, @ast_fold) -> (T, Span) {
     let result: @fn(&T, Span, @ast_fold) -> (T, Span) = |x, s, fld| {
@@ -496,8 +498,6 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
     }
     let fold_field = |x| fold_field_(x, fld);
 
-    let fold_mac = |x| fold_mac_(x, fld);
-
     match *e {
         ExprVstore(e, v) => {
             ExprVstore(fld.fold_expr(e), v)
@@ -544,7 +544,7 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
         ExprDoBody(f) => ExprDoBody(fld.fold_expr(f)),
         ExprLit(_) => (*e).clone(),
         ExprCast(expr, ref ty) => {
-            ExprCast(fld.fold_expr(expr), (*ty).clone())
+            ExprCast(fld.fold_expr(expr), fld.fold_ty(ty))
         }
         ExprAddrOf(m, ohs) => ExprAddrOf(m, fld.fold_expr(ohs)),
         ExprIf(cond, ref tr, fl) => {
@@ -629,7 +629,7 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
                 .. (*a).clone()
             })
         }
-        ExprMac(ref mac) => ExprMac(fold_mac(mac)),
+        ExprMac(ref mac) => ExprMac(fld.fold_mac(mac)),
         ExprStruct(ref path, ref fields, maybe_expr) => {
             ExprStruct(
                 fld.fold_path(path),
@@ -642,7 +642,6 @@ fn fold_field_(field: Field, fld: @ast_fold) -> Field {
 }
 
 pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ {
-    let fold_mac = |x| fold_mac_(x, fld);
     fn fold_mt(mt: &mt, fld: @ast_fold) -> mt {
         mt {
             ty: ~fld.fold_ty(mt.ty),
@@ -698,7 +697,7 @@ fn fold_opt_bounds(b: &Option<OptVec<TyParamBound>>, fld: @ast_fold)
             )
         }
         ty_typeof(e) => ty_typeof(fld.fold_expr(e)),
-        ty_mac(ref mac) => ty_mac(fold_mac(mac))
+        ty_mac(ref mac) => ty_mac(fld.fold_mac(mac))
     }
 }
 
@@ -785,6 +784,19 @@ fn noop_fold_local(l: @Local, fld: @ast_fold) -> @Local {
     }
 }
 
+// the default macro traversal. visit the path
+// using fold_path, and the tts using fold_tts,
+// and the span using new_span
+fn noop_fold_mac(m: &mac_, fld: @ast_fold) -> mac_ {
+    match *m {
+        mac_invoc_tt(ref p,ref tts,ctxt) =>
+        mac_invoc_tt(fld.fold_path(p),
+                     fold_tts(*tts,fld),
+                     ctxt)
+    }
+}
+
+
 /* temporarily eta-expand because of a compiler bug with using `fn<T>` as a
    value */
 fn noop_map_exprs(f: @fn(@Expr) -> @Expr, es: &[@Expr]) -> ~[@Expr] {
@@ -817,6 +829,7 @@ pub fn default_ast_fold() -> ast_fold_fns {
         fold_ident: noop_fold_ident,
         fold_path: noop_fold_path,
         fold_local: noop_fold_local,
+        fold_mac: wrap(noop_fold_mac),
         map_exprs: noop_map_exprs,
         new_id: noop_id,
         new_span: noop_span,
@@ -922,6 +935,10 @@ fn fold_path(@self, x: &Path) -> Path {
     fn fold_local(@self, x: @Local) -> @Local {
         (self.fold_local)(x, self as @ast_fold)
     }
+    fn fold_mac(@self, x: &mac) -> mac {
+        let (n, s) = (self.fold_mac)(&x.node, x.span, self as @ast_fold);
+        Spanned { node: n, span: (self.new_span)(s) }
+    }
     fn map_exprs(@self,
                  f: @fn(@Expr) -> @Expr,
                  e: &[@Expr])
@@ -946,6 +963,8 @@ fn fold_attributes(&self, attrs: ~[Attribute]) -> ~[Attribute] {
     }
 }
 
+// brson agrees with me that this function's existence is probably
+// not a good or useful thing.
 pub fn make_fold(afp: ast_fold_fns) -> @ast_fold {
     afp as @ast_fold
 }
@@ -1018,4 +1037,15 @@ macro_rules! assert_pred (
                                     token::get_ident_interner()),
                      ~"zz!zz((zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+)))");
     }
+
+    // and in cast expressions... this appears to be an existing bug.
+    #[test] fn ident_transformation_in_types () {
+        let zz_fold = fun_to_ident_folder(to_zz());
+        let ast = string_to_crate(@"fn a() {let z = 13 as int;}");
+        assert_pred!(matches_codepattern,
+                     "matches_codepattern",
+                     pprust::to_str(&zz_fold.fold_crate(ast),fake_print_crate,
+                                    token::get_ident_interner()),
+                     ~"fn zz(){let zz=13 as zz;}");
+    }
 }
index 51c5522ae2f7c2be972808d1b7d186a5d277d747..8b11a25f13ce38f655a79598a8a9ac90d8cbab1c 100644 (file)
@@ -21,7 +21,7 @@
 use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
 use ast::{BlockCheckMode, UnBox};
 use ast::{Crate, CrateConfig, Decl, DeclItem};
-use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, enum_def, explicit_self};
+use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, enum_def, explicit_self};
 use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
 use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock};
 use ast::{ExprBreak, ExprCall, ExprCast, ExprDoBody};
@@ -1875,7 +1875,7 @@ pub fn parse_bottom_expr(&self) -> @Expr {
                                                 |p| p.parse_token_tree());
                 let hi = self.span.hi;
 
-                return self.mk_mac_expr(lo, hi, mac_invoc_tt(pth, tts));
+                return self.mk_mac_expr(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT));
             } else if *self.token == token::LBRACE {
                 // This might be a struct literal.
                 if self.looking_at_record_literal() {
@@ -3197,14 +3197,14 @@ fn check_expected_item(p: &Parser, found_attrs: bool) {
 
             if id == token::special_idents::invalid {
                 return @spanned(lo, hi, StmtMac(
-                    spanned(lo, hi, mac_invoc_tt(pth, tts)), false));
+                    spanned(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT)), false));
             } else {
                 // if it has a special ident, it's definitely an item
                 return @spanned(lo, hi, StmtDecl(
                     @spanned(lo, hi, DeclItem(
                         self.mk_item(
                             lo, hi, id /*id is good here*/,
-                            item_mac(spanned(lo, hi, mac_invoc_tt(pth, tts))),
+                            item_mac(spanned(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT))),
                             inherited, ~[/*no attrs*/]))),
                     self.get_id()));
             }
@@ -3518,7 +3518,10 @@ pub fn parse_fn_decl(&self) -> fn_decl {
     }
 
     fn is_self_ident(&self) -> bool {
-        *self.token == token::IDENT(special_idents::self_, false)
+        match *self.token {
+          token::IDENT(id, false) => id.name == special_idents::self_.name,
+          _ => false
+        }
     }
 
     fn expect_self_ident(&self) {
@@ -4806,7 +4809,7 @@ fn parse_macro_use_or_failure(
                 _ => self.fatal("expected open delimiter")
             };
             // single-variant-enum... :
-            let m = ast::mac_invoc_tt(pth, tts);
+            let m = ast::mac_invoc_tt(pth, tts, EMPTY_CTXT);
             let m: ast::mac = codemap::Spanned { node: m,
                                              span: mk_sp(self.span.lo,
                                                          self.span.hi) };
index 591b4b10bd31451d8bbe5e894a65a6ef0626d845..6b3a95a14f8e6cb87b13fe05aaaff446b81d838a 100644 (file)
@@ -9,17 +9,15 @@
 // except according to those terms.
 
 use ast;
-use ast::Name;
+use ast::{Name, Mrk};
 use ast_util;
 use parse::token;
 use util::interner::StrInterner;
 use util::interner;
 
+use std::cast;
 use std::char;
-use std::cmp::Equiv;
 use std::local_data;
-use std::rand;
-use std::rand::RngUtil;
 
 #[deriving(Clone, Encodable, Decodable, Eq, IterBytes)]
 pub enum binop {
@@ -309,22 +307,23 @@ pub fn is_bar(t: &Token) -> bool {
     match *t { BINOP(OR) | OROR => true, _ => false }
 }
 
-
 pub mod special_idents {
     use ast::Ident;
 
-    pub static underscore : Ident = Ident { name: 0, ctxt: 0};
+    pub static underscore : Ident = Ident { name: 0, ctxt: 0}; // apparently unused?
     pub static anon : Ident = Ident { name: 1, ctxt: 0};
     pub static invalid : Ident = Ident { name: 2, ctxt: 0}; // ''
-    pub static unary : Ident = Ident { name: 3, ctxt: 0};
-    pub static not_fn : Ident = Ident { name: 4, ctxt: 0};
-    pub static idx_fn : Ident = Ident { name: 5, ctxt: 0};
-    pub static unary_minus_fn : Ident = Ident { name: 6, ctxt: 0};
+    pub static unary : Ident = Ident { name: 3, ctxt: 0}; // apparently unused?
+    pub static not_fn : Ident = Ident { name: 4, ctxt: 0}; // apparently unused?
+    pub static idx_fn : Ident = Ident { name: 5, ctxt: 0}; // apparently unused?
+    pub static unary_minus_fn : Ident = Ident { name: 6, ctxt: 0}; // apparently unused?
     pub static clownshoes_extensions : Ident = Ident { name: 7, ctxt: 0};
 
     pub static self_ : Ident = Ident { name: 8, ctxt: 0}; // 'self'
 
     /* for matcher NTs */
+    // none of these appear to be used, but perhaps references to
+    // these are artificially fabricated by the macro system....
     pub static item : Ident = Ident { name: 9, ctxt: 0};
     pub static block : Ident = Ident { name: 10, ctxt: 0};
     pub static stmt : Ident = Ident { name: 11, ctxt: 0};
@@ -336,7 +335,7 @@ pub mod special_idents {
     pub static tt : Ident = Ident { name: 17, ctxt: 0};
     pub static matchers : Ident = Ident { name: 18, ctxt: 0};
 
-    pub static str : Ident = Ident { name: 19, ctxt: 0}; // for the type
+    pub static str : Ident = Ident { name: 19, ctxt: 0}; // for the type // apparently unused?
 
     /* outside of libsyntax */
     pub static arg : Ident = Ident { name: 20, ctxt: 0};
@@ -349,10 +348,32 @@ pub mod special_idents {
     pub static statik : Ident = Ident { name: 27, ctxt: 0};
     pub static clownshoes_foreign_mod: Ident = Ident { name: 28, ctxt: 0};
     pub static unnamed_field: Ident = Ident { name: 29, ctxt: 0};
-    pub static c_abi: Ident = Ident { name: 30, ctxt: 0};
+    pub static c_abi: Ident = Ident { name: 30, ctxt: 0}; // apparently unused?
     pub static type_self: Ident = Ident { name: 31, ctxt: 0};    // `Self`
 }
 
+// here are the ones that actually occur in the source. Maybe the rest
+// should be removed?
+/*
+special_idents::anon
+special_idents::arg
+special_idents::blk
+special_idents::clownshoe_abi
+special_idents::clownshoe_stack_shim
+special_idents::clownshoes_extensions
+special_idents::clownshoes_foreign_mod
+special_idents::descrim
+special_idents::invalid
+special_idents::main
+special_idents::matchers
+special_idents::opaque
+special_idents::self_
+special_idents::statik
+special_idents::tt
+special_idents::type_self
+special_idents::unnamed_field
+*/
+
 /**
  * Maps a token to a record specifying the corresponding binary
  * operator
@@ -381,30 +402,8 @@ pub fn token_to_binop(tok: &Token) -> Option<ast::BinOp> {
   }
 }
 
-pub struct ident_interner {
-    priv interner: StrInterner,
-}
-
-impl ident_interner {
-    pub fn intern(&self, val: &str) -> Name {
-        self.interner.intern(val)
-    }
-    pub fn gensym(&self, val: &str) -> Name {
-        self.interner.gensym(val)
-    }
-    pub fn get(&self, idx: Name) -> @str {
-        self.interner.get(idx)
-    }
-    // is this really something that should be exposed?
-    pub fn len(&self) -> uint {
-        self.interner.len()
-    }
-    pub fn find_equiv<Q:Hash + IterBytes + Equiv<@str>>(&self, val: &Q)
-                                                     -> Option<Name> {
-        self.interner.find_equiv(val)
-    }
-}
-
+// looks like we can get rid of this completely...
+pub type ident_interner = StrInterner;
 
 // return a fresh interner, preloaded with special identifiers.
 fn mk_fresh_ident_interner() -> @ident_interner {
@@ -485,9 +484,7 @@ fn mk_fresh_ident_interner() -> @ident_interner {
         "typeof",             // 67
     ];
 
-    @ident_interner {
-        interner: interner::StrInterner::prefill(init_vec)
-    }
+    @interner::StrInterner::prefill(init_vec)
 }
 
 // if an interner exists in TLS, return it. Otherwise, prepare a
@@ -508,7 +505,7 @@ pub fn get_ident_interner() -> @ident_interner {
 /* for when we don't care about the contents; doesn't interact with TLD or
    serialization */
 pub fn mk_fake_ident_interner() -> @ident_interner {
-    @ident_interner { interner: interner::StrInterner::new() }
+    @interner::StrInterner::new()
 }
 
 // maps a string to its interned representation
@@ -543,18 +540,44 @@ pub fn gensym_ident(str : &str) -> ast::Ident {
     ast::Ident::new(gensym(str))
 }
 
+// create a fresh name that maps to the same string as the old one.
+// note that this guarantees that str_ptr_eq(ident_to_str(src),interner_get(fresh_name(src)));
+// that is, that the new name and the old one are connected to ptr_eq strings.
+pub fn fresh_name(src : &ast::Ident) -> Name {
+    let interner = get_ident_interner();
+    interner.gensym_copy(src.name)
+    // following: debug version. Could work in final except that it's incompatible with
+    // good error messages and uses of struct names in ambiguous could-be-binding
+    // locations. Also definitely destroys the guarantee given above about ptr_eq.
+    /*let num = rand::rng().gen_uint_range(0,0xffff);
+    gensym(fmt!("%s_%u",ident_to_str(src),num))*/
+}
+
+// it looks like there oughta be a str_ptr_eq fn, but no one bothered to implement it?
+
+// determine whether two @str values are pointer-equal
+pub fn str_ptr_eq(a : @str, b : @str) -> bool {
+    unsafe {
+        let p : uint = cast::transmute(a);
+        let q : uint = cast::transmute(b);
+        let result = p == q;
+        // got to transmute them back, to make sure the ref count is correct:
+        let _junk1 : @str = cast::transmute(p);
+        let _junk2 : @str = cast::transmute(q);
+        result
+    }
+}
+
+// return true when two identifiers refer (through the intern table) to the same ptr_eq
+// string. This is used to compare identifiers in places where hygienic comparison is
+// not wanted (i.e. not lexical vars).
+pub fn ident_spelling_eq(a : &ast::Ident, b : &ast::Ident) -> bool {
+    str_ptr_eq(interner_get(a.name),interner_get(b.name))
+}
 
-// create a fresh name. In principle, this is just a
-// gensym, but for debugging purposes, you'd like the
-// resulting name to have a suggestive stringify, without
-// paying the cost of guaranteeing that the name is
-// truly unique.  I'm going to try to strike a balance
-// by using a gensym with a name that has a random number
-// at the end. So, the gensym guarantees the uniqueness,
-// and the int helps to avoid confusion.
-pub fn fresh_name(src_name : &str) -> Name {
-    let num = rand::rng().gen_uint_range(0,0xffff);
-   gensym(fmt!("%s_%u",src_name,num))
+// create a fresh mark.
+pub fn fresh_mark() -> Mrk {
+    gensym("mark")
 }
 
 /**
@@ -694,12 +717,48 @@ 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,_)) =>
+        ast_util::mtwt_resolve(id1) == ast_util::mtwt_resolve(id2),
+        _ => *t1 == *t2
+    }
+}
+
+
 #[cfg(test)]
 mod test {
     use super::*;
-    #[test] fn t1() {
-        let a = fresh_name("ghi");
-        printfln!("interned name: %u,\ntextual name: %s\n",
-                  a, interner_get(a));
+    use ast;
+    use ast_util;
+
+    fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
+        ast::Ident{name:id.name,ctxt:ast_util::new_mark(m,id.ctxt)}
     }
+
+    #[test] fn mtwt_token_eq_test() {
+        assert!(mtwt_token_eq(&GT,&GT));
+        let a = str_to_ident("bac");
+        let a1 = mark_ident(a,92);
+        assert!(mtwt_token_eq(&IDENT(a,true),&IDENT(a1,false)));
+    }
+
+
+    #[test] fn str_ptr_eq_tests(){
+        let a = @"abc";
+        let b = @"abc";
+        let c = a;
+        assert!(str_ptr_eq(a,c));
+        assert!(!str_ptr_eq(a,b));
+    }
+
+    #[test] fn fresh_name_pointer_sharing() {
+        let ghi = str_to_ident("ghi");
+        assert_eq!(ident_to_str(&ghi),@"ghi");
+        assert!(str_ptr_eq(ident_to_str(&ghi),ident_to_str(&ghi)))
+        let fresh = ast::Ident::new(fresh_name(&ghi));
+        assert_eq!(ident_to_str(&fresh),@"ghi");
+        assert!(str_ptr_eq(ident_to_str(&ghi),ident_to_str(&fresh)));
+    }
+
 }
index 32cf30fd3a00d5eff5a10daf8f536da60714f19b..f440e0a177110b36a600fb5213262f083b328663 100644 (file)
@@ -619,7 +619,8 @@ pub fn print_item(s: @ps, item: &ast::item) {
         }
         bclose(s, item.span);
       }
-      ast::item_mac(codemap::Spanned { node: ast::mac_invoc_tt(ref pth, ref tts),
+      // I think it's reasonable to hide the context here:
+      ast::item_mac(codemap::Spanned { node: ast::mac_invoc_tt(ref pth, ref tts, _),
                                    _}) => {
         print_visibility(s, item.vis);
         print_path(s, pth, false);
@@ -1021,7 +1022,8 @@ fn do_else(s: @ps, els: Option<@ast::Expr>) {
 
 pub fn print_mac(s: @ps, m: &ast::mac) {
     match m.node {
-      ast::mac_invoc_tt(ref pth, ref tts) => {
+      // I think it's reasonable to hide the ctxt here:
+      ast::mac_invoc_tt(ref pth, ref tts, _) => {
         print_path(s, pth, false);
         word(s.s, "!");
         popen(s);
@@ -1924,8 +1926,8 @@ pub fn print_arg(s: @ps, input: &ast::arg) {
         match input.pat.node {
             ast::PatIdent(_, ref path, _) if
                 path.segments.len() == 1 &&
-                path.segments[0].identifier ==
-                    parse::token::special_idents::invalid => {
+                path.segments[0].identifier.name ==
+                    parse::token::special_idents::invalid.name => {
                 // Do nothing.
             }
             _ => {
index 46676ce1093fba81e917b8a8aebcc535d2bfb5b9..2b1e7eaa9b26d592a0fd6dd98e449f8a07d7817d 100644 (file)
@@ -117,6 +117,23 @@ pub fn gensym(&self, val: &str) -> uint {
         new_idx
     }
 
+    // I want these gensyms to share name pointers
+    // with existing entries. This would be automatic,
+    // except that the existing gensym creates its
+    // own managed ptr using to_managed. I think that
+    // adding this utility function is the most
+    // lightweight way to get what I want, though not
+    // necessarily the cleanest.
+
+    // create a gensym with the same name as an existing
+    // entry.
+    pub fn gensym_copy(&self, idx : uint) -> uint {
+        let new_idx = self.len();
+        // leave out of map to avoid colliding
+        self.vect.push(self.vect[idx]);
+        new_idx
+    }
+
     // this isn't "pure" in the traditional sense, because it can go from
     // failing to returning a value as items are interned. But for typestate,
     // where we first check a pred and then rely on it, ceasing to fail is ok.
@@ -144,23 +161,23 @@ fn i1 () {
     }
 
     #[test]
-    fn i2 () {
+    fn interner_tests () {
         let i : Interner<@str> = Interner::new();
         // first one is zero:
-        assert_eq!(i.intern (@"dog"), 0);
+        assert_eq!(i.intern(@"dog"), 0);
         // re-use gets the same entry:
-        assert_eq!(i.intern (@"dog"), 0);
+        assert_eq!(i.intern(@"dog"), 0);
         // different string gets a different #:
-        assert_eq!(i.intern (@"cat"), 1);
-        assert_eq!(i.intern (@"cat"), 1);
+        assert_eq!(i.intern(@"cat"), 1);
+        assert_eq!(i.intern(@"cat"), 1);
         // dog is still at zero
-        assert_eq!(i.intern (@"dog"), 0);
+        assert_eq!(i.intern(@"dog"), 0);
         // gensym gets 3
-        assert_eq!(i.gensym (@"zebra" ), 2);
+        assert_eq!(i.gensym(@"zebra" ), 2);
         // gensym of same string gets new number :
         assert_eq!(i.gensym (@"zebra" ), 3);
         // gensym of *existing* string gets new number:
-        assert_eq!(i.gensym (@"dog"), 4);
+        assert_eq!(i.gensym(@"dog"), 4);
         assert_eq!(i.get(0), @"dog");
         assert_eq!(i.get(1), @"cat");
         assert_eq!(i.get(2), @"zebra");
@@ -176,4 +193,34 @@ fn i3 () {
         assert_eq!(i.get(2), @"Carol");
         assert_eq!(i.intern(@"Bob"), 1);
     }
+
+    #[test]
+    fn string_interner_tests() {
+        let i : StrInterner = StrInterner::new();
+        // first one is zero:
+        assert_eq!(i.intern("dog"), 0);
+        // re-use gets the same entry:
+        assert_eq!(i.intern ("dog"), 0);
+        // different string gets a different #:
+        assert_eq!(i.intern("cat"), 1);
+        assert_eq!(i.intern("cat"), 1);
+        // dog is still at zero
+        assert_eq!(i.intern("dog"), 0);
+        // gensym gets 3
+        assert_eq!(i.gensym("zebra"), 2);
+        // gensym of same string gets new number :
+        assert_eq!(i.gensym("zebra"), 3);
+        // gensym of *existing* string gets new number:
+        assert_eq!(i.gensym("dog"), 4);
+        // gensym tests again with gensym_copy:
+        assert_eq!(i.gensym_copy(2), 5);
+        assert_eq!(i.get(5), @"zebra");
+        assert_eq!(i.gensym_copy(2), 6);
+        assert_eq!(i.get(6), @"zebra");
+        assert_eq!(i.get(0), @"dog");
+        assert_eq!(i.get(1), @"cat");
+        assert_eq!(i.get(2), @"zebra");
+        assert_eq!(i.get(3), @"zebra");
+        assert_eq!(i.get(4), @"dog");
+    }
 }
index ca1e53f7fcd9e5c8bdef7143c930e7ae86625c2c..23396c06a9a17c68db0201ee533457cb3622a84c 100644 (file)
@@ -22,6 +22,12 @@ pub fn string_to_tts_and_sess (source_str : @str) -> (~[ast::token_tree],@mut Pa
     (filemap_to_tts(ps,string_to_filemap(ps,source_str,@"bogofile")),ps)
 }
 
+// map a string to tts, using a made-up filename:
+pub fn string_to_tts(source_str : @str) -> ~[ast::token_tree] {
+    let (tts,_) = string_to_tts_and_sess(source_str);
+    tts
+}
+
 pub fn string_to_parser_and_sess(source_str: @str) -> (Parser,@mut ParseSess) {
     let ps = new_parse_sess(None);
     (new_parser_from_source_str(ps,~[],@"bogofile",source_str),ps)
@@ -40,12 +46,19 @@ fn with_error_checking_parse<T>(s: @str, f: &fn(&mut Parser) -> T) -> T {
     x
 }
 
+// parse a string, return a crate.
 pub fn string_to_crate (source_str : @str) -> @ast::Crate {
     do with_error_checking_parse(source_str) |p| {
         p.parse_crate_mod()
     }
 }
 
+// parse a string, return a crate and the ParseSess
+pub fn string_to_crate_and_sess (source_str : @str) -> (@ast::Crate,@mut ParseSess) {
+    let (p,ps) = string_to_parser_and_sess(source_str);
+    (p.parse_crate_mod(),ps)
+}
+
 // parse a string, return an expr
 pub fn string_to_expr (source_str : @str) -> @ast::Expr {
     do with_error_checking_parse(source_str) |p| {
@@ -60,14 +73,6 @@ pub fn string_to_item (source_str : @str) -> Option<@ast::item> {
     }
 }
 
-// parse a string, return an item and the ParseSess
-pub fn string_to_item_and_sess (source_str : @str) -> (Option<@ast::item>,@mut ParseSess) {
-    let (p,ps) = string_to_parser_and_sess(source_str);
-    let io = p.parse_item(~[]);
-    p.abort_if_errors();
-    (io,ps)
-}
-
 // parse a string, return a stmt
 pub fn string_to_stmt(source_str : @str) -> @ast::Stmt {
     do with_error_checking_parse(source_str) |p| {
index 6735d623e6cdf95bb376fddc4e94529165502263..5bfef47902ba790ff6ab6db54359e46c9ec8d2e9 100644 (file)
 use std::vec;
 
 macro_rules! bench (
-    ($id:ident) => (maybe_run_test(argv, stringify!($id).to_owned(), $id))
+    ($argv:expr, $id:ident) => (maybe_run_test($argv, stringify!($id).to_owned(), $id))
 )
 
 fn main() {
     let argv = os::args();
     let _tests = argv.slice(1, argv.len());
 
-    bench!(shift_push);
-    bench!(read_line);
-    bench!(vec_plus);
-    bench!(vec_append);
-    bench!(vec_push_all);
-    bench!(is_utf8_ascii);
-    bench!(is_utf8_multibyte);
+    bench!(argv, shift_push);
+    bench!(argv, read_line);
+    bench!(argv, vec_plus);
+    bench!(argv, vec_append);
+    bench!(argv, vec_push_all);
+    bench!(argv, is_utf8_ascii);
+    bench!(argv, is_utf8_multibyte);
 }
 
 fn maybe_run_test(argv: &[~str], name: ~str, test: &fn()) {
diff --git a/src/test/run-pass/hygiene-dodging-1.rs b/src/test/run-pass/hygiene-dodging-1.rs
new file mode 100644 (file)
index 0000000..55e15cc
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod x {
+    pub fn g() -> uint {14}
+}
+
+fn main(){
+    // should *not* shadow the module x:
+    let x = 9;
+    // use it to avoid warnings:
+    x+3;
+    assert_eq!(x::g(),14);
+}
diff --git a/src/test/run-pass/let-var-hygiene.rs b/src/test/run-pass/let-var-hygiene.rs
new file mode 100644 (file)
index 0000000..1e29d2e
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2012 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// shouldn't affect evaluation of $ex:
+macro_rules! bad_macro (($ex:expr) => ({let _x = 9; $ex}))
+fn main() {
+    let _x = 8;
+    assert_eq!(bad_macro!(_x),8)
+}
index 819bcbf53f588bcce72e37ba78b6219c93805a34..60294e6f21e796b6a3259c4aa2a98f7da35bc02f 100644 (file)
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// xfail-test
+// this now fails (correctly, I claim) because hygiene prevents
+// the assembled identifier from being a reference to the binding.
 
 pub fn main() {
     let asdf_fdsa = ~"<.<";