]> git.lizzy.rs Git - rust.git/commitdiff
Avoid comparing fields by name when possible
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 5 Apr 2018 00:20:21 +0000 (03:20 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 12 Apr 2018 20:06:03 +0000 (23:06 +0300)
Resolve them into field indices once and then use those resolutions

+ Fix rebase

27 files changed:
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/mod.rs
src/librustc/ich/impls_hir.rs
src/librustc/middle/dead.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/mem_categorization.rs
src/librustc/ty/context.rs
src/librustc/ty/mod.rs
src/librustc/ty/util.rs
src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_borrowck/borrowck/move_data.rs
src/librustc_lint/builtin.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/pattern/mod.rs
src/librustc_privacy/lib.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/lib.rs
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/writeback.rs
src/librustc_typeck/collect.rs
src/libsyntax/ext/build.rs
src/libsyntax/parse/parser.rs
src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs

index 0a7f0e4dc4c6cebf9348c61dda2c15ac5b2cb4d5..be9f8b8dac5c05bbced574cf89dacc6d2191eba8 100644 (file)
@@ -658,6 +658,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
         PatKind::Struct(ref qpath, ref fields, _) => {
             visitor.visit_qpath(qpath, pattern.id, pattern.span);
             for field in fields {
+                visitor.visit_id(field.node.id);
                 visitor.visit_name(field.span, field.node.name);
                 visitor.visit_pat(&field.node.pat)
             }
@@ -959,6 +960,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
         ExprStruct(ref qpath, ref fields, ref optional_base) => {
             visitor.visit_qpath(qpath, expression.id, expression.span);
             for field in fields {
+                visitor.visit_id(field.id);
                 visitor.visit_name(field.name.span, field.name.node);
                 visitor.visit_expr(&field.expr)
             }
index 262c307feedcd91d3453fdc693c651f45ed7c265..fee076acb207eadde431c66a51b1095eb65f9385 100644 (file)
@@ -2100,6 +2100,7 @@ fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::Stru
 
     fn lower_field(&mut self, f: &Field) -> hir::Field {
         hir::Field {
+            id: self.next_id().node_id,
             name: respan(f.ident.span, self.lower_ident(f.ident)),
             expr: P(self.lower_expr(&f.expr)),
             span: f.span,
@@ -2863,6 +2864,7 @@ fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
                     .map(|f| Spanned {
                         span: f.span,
                         node: hir::FieldPat {
+                            id: self.next_id().node_id,
                             name: self.lower_ident(f.node.ident),
                             pat: self.lower_pat(&f.node.pat),
                             is_shorthand: f.node.is_shorthand,
@@ -3741,6 +3743,7 @@ fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Ar
 
     fn field(&mut self, name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field {
         hir::Field {
+            id: self.next_id().node_id,
             name: Spanned { node: name, span },
             span,
             expr,
index 79b39be3eb20885a7e95e7bd4fa8c22e55eebeea..e6080fad91d597f60410ffd2e989951490c1b835 100644 (file)
@@ -827,6 +827,7 @@ pub fn walk<F>(&self, mut it: F) -> bool
 /// except is_shorthand is true
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct FieldPat {
+    pub id: NodeId,
     /// The identifier for the field
     pub name: Name,
     /// The pattern the field is destructured to
@@ -1172,6 +1173,7 @@ pub struct Arm {
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct Field {
+    pub id: NodeId,
     pub name: Spanned<Name>,
     pub expr: P<Expr>,
     pub span: Span,
index ec573e3d681055b062d78a6a3c75726648ed4d7b..4a001802eacb48c889fa1546418056da900cdea4 100644 (file)
@@ -420,11 +420,23 @@ fn hash_stable<W: StableHasherResult>(&self,
 }
 
 impl_stable_hash_for_spanned!(hir::FieldPat);
-impl_stable_hash_for!(struct hir::FieldPat {
-    name,
-    pat,
-    is_shorthand
-});
+
+impl<'a> HashStable<StableHashingContext<'a>> for hir::FieldPat {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::FieldPat {
+            id: _,
+            name,
+            ref pat,
+            is_shorthand,
+        } = *self;
+
+        name.hash_stable(hcx, hasher);
+        pat.hash_stable(hcx, hasher);
+        is_shorthand.hash_stable(hcx, hasher);
+    }
+}
 
 impl_stable_hash_for!(enum hir::BindingAnnotation {
     Unannotated,
@@ -507,12 +519,24 @@ fn hash_stable<W: StableHasherResult>(&self,
     body
 });
 
-impl_stable_hash_for!(struct hir::Field {
-    name,
-    expr,
-    span,
-    is_shorthand
-});
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Field {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::Field {
+            id: _,
+            name,
+            ref expr,
+            span,
+            is_shorthand,
+        } = *self;
+
+        name.hash_stable(hcx, hasher);
+        expr.hash_stable(hcx, hasher);
+        span.hash_stable(hcx, hasher);
+        is_shorthand.hash_stable(hcx, hasher);
+    }
+}
 
 impl_stable_hash_for_spanned!(ast::Name);
 
index 5800988344ad0e52068f895c7e0cabc19796e0f2..9ec3d2e2460e944ba41900309cf4e92929e812ce 100644 (file)
@@ -13,7 +13,7 @@
 // from live codes are live, and everything else is dead.
 
 use hir::map as hir_map;
-use hir::{self, Item_, PatKind};
+use hir::{self, PatKind};
 use hir::intravisit::{self, Visitor, NestedVisitorMap};
 use hir::itemlikevisit::ItemLikeVisitor;
 
@@ -99,10 +99,11 @@ fn lookup_and_handle_method(&mut self, id: hir::HirId) {
         self.check_def_id(self.tables.type_dependent_defs()[id].def_id());
     }
 
-    fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
+    fn handle_field_access(&mut self, lhs: &hir::Expr, node_id: ast::NodeId) {
         match self.tables.expr_ty_adjusted(lhs).sty {
             ty::TyAdt(def, _) => {
-                self.insert_def_id(def.non_enum_variant().field_named(name).did);
+                let index = self.tcx.field_index(node_id, self.tables);
+                self.insert_def_id(def.non_enum_variant().fields[index].did);
             }
             ty::TyTuple(..) => {}
             _ => span_bug!(lhs.span, "named field access on non-ADT"),
@@ -119,7 +120,8 @@ fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, def: Def,
             if let PatKind::Wild = pat.node.pat.node {
                 continue;
             }
-            self.insert_def_id(variant.field_named(pat.node.name).did);
+            let index = self.tcx.field_index(pat.node.id, self.tables);
+            self.insert_def_id(variant.fields[index].did);
         }
     }
 
@@ -182,18 +184,11 @@ fn visit_node(&mut self, node: &hir_map::Node<'tcx>) {
         self.inherited_pub_visibility = had_inherited_pub_visibility;
     }
 
-    fn mark_as_used_if_union(&mut self, did: DefId, fields: &hir::HirVec<hir::Field>) {
-        if let Some(node_id) = self.tcx.hir.as_local_node_id(did) {
-            if let Some(hir_map::NodeItem(item)) = self.tcx.hir.find(node_id) {
-                if let Item_::ItemUnion(ref variant, _) = item.node {
-                    if variant.fields().len() > 1 {
-                        for field in variant.fields() {
-                            if fields.iter().find(|x| x.name.node == field.name).is_some() {
-                                self.live_symbols.insert(field.id);
-                            }
-                        }
-                    }
-                }
+    fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &hir::HirVec<hir::Field>) {
+        if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() {
+            for field in fields {
+                let index = self.tcx.field_index(field.id, self.tables);
+                self.insert_def_id(adt.non_enum_variant().fields[index].did);
             }
         }
     }
@@ -233,14 +228,12 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
             hir::ExprMethodCall(..) => {
                 self.lookup_and_handle_method(expr.hir_id);
             }
-            hir::ExprField(ref lhs, ref name) => {
-                self.handle_field_access(&lhs, name.node);
+            hir::ExprField(ref lhs, ..) => {
+                self.handle_field_access(&lhs, expr.id);
             }
             hir::ExprStruct(_, ref fields, _) => {
-                if let ty::TypeVariants::TyAdt(ref def, _) = self.tables.expr_ty(expr).sty {
-                    if def.is_union() {
-                        self.mark_as_used_if_union(def.did, fields);
-                    }
+                if let ty::TypeVariants::TyAdt(ref adt, _) = self.tables.expr_ty(expr).sty {
+                    self.mark_as_used_if_union(adt, fields);
                 }
             }
             _ => ()
index fb83e563ffcd28e5488ff826589aba7bb410586c..2cc5a4a8fe639f33d9ed125cd19083064f6bee4d 100644 (file)
@@ -659,11 +659,15 @@ fn walk_struct_expr(&mut self,
         match with_cmt.ty.sty {
             ty::TyAdt(adt, substs) if adt.is_struct() => {
                 // Consume those fields of the with expression that are needed.
-                for with_field in &adt.non_enum_variant().fields {
-                    if !contains_field_named(with_field, fields) {
+                for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
+                    let is_mentioned = fields.iter().any(|f| {
+                        self.tcx().field_index(f.id, self.mc.tables) == f_index
+                    });
+                    if !is_mentioned {
                         let cmt_field = self.mc.cat_field(
                             &*with_expr,
                             with_cmt.clone(),
+                            f_index,
                             with_field.name,
                             with_field.ty(self.tcx(), substs)
                         );
@@ -687,14 +691,6 @@ fn walk_struct_expr(&mut self,
         // walk the with expression so that complex expressions
         // are properly handled.
         self.walk_expr(with_expr);
-
-        fn contains_field_named(field: &ty::FieldDef,
-                                fields: &[hir::Field])
-                                -> bool
-        {
-            fields.iter().any(
-                |f| f.name.node == field.name)
-        }
     }
 
     // Invoke the appropriate delegate calls for anything that gets
index c7449325f756166d142b1a9fd22f90a1a8d844de..6f41f07dce8a779efe6e602ae1f70dc5260f99d3 100644 (file)
@@ -84,6 +84,7 @@
 use syntax_pos::Span;
 
 use std::fmt;
+use std::hash::{Hash, Hasher};
 use rustc_data_structures::sync::Lrc;
 use std::rc::Rc;
 use util::nodemap::ItemLocalSet;
@@ -132,9 +133,22 @@ pub enum InteriorKind {
     InteriorElement(InteriorOffsetKind),
 }
 
-// FIXME: Use actual index instead of `ast::Name` with questionable hygiene
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct FieldIndex(pub ast::Name);
+// Contains index of a field that is actually used for loan path comparisons and
+// string representation of the field that should be used only for diagnostics.
+#[derive(Clone, Copy, Eq)]
+pub struct FieldIndex(pub usize, pub Name);
+
+impl PartialEq for FieldIndex {
+    fn eq(&self, rhs: &Self) -> bool {
+        self.0 == rhs.0
+    }
+}
+
+impl Hash for FieldIndex {
+    fn hash<H: Hasher>(&self, h: &mut H) {
+        self.0.hash(h)
+    }
+}
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum InteriorOffsetKind {
@@ -195,7 +209,7 @@ pub enum ImmutabilityBlame<'tcx> {
 }
 
 impl<'tcx> cmt_<'tcx> {
-    fn resolve_field(&self, field_name: Name) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
+    fn resolve_field(&self, field_index: usize) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
     {
         let adt_def = match self.ty.sty {
             ty::TyAdt(def, _) => def,
@@ -212,7 +226,7 @@ fn resolve_field(&self, field_name: Name) -> Option<(&'tcx ty::AdtDef, &'tcx ty:
                 &adt_def.variants[0]
             }
         };
-        Some((adt_def, variant_def.field_named(field_name)))
+        Some((adt_def, &variant_def.fields[field_index]))
     }
 
     pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
@@ -639,7 +653,8 @@ pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
                    expr.id,
                    expr,
                    base_cmt);
-            Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
+            let f_index = self.tcx.field_index(expr.id, self.tables);
+            Ok(self.cat_field(expr, base_cmt, f_index, f_name.node, expr_ty))
           }
 
           hir::ExprIndex(ref base, _) => {
@@ -967,6 +982,7 @@ pub fn cat_rvalue(&self,
     pub fn cat_field<N:ast_node>(&self,
                                  node: &N,
                                  base_cmt: cmt<'tcx>,
+                                 f_index: usize,
                                  f_name: Name,
                                  f_ty: Ty<'tcx>)
                                  -> cmt<'tcx> {
@@ -974,7 +990,7 @@ pub fn cat_field<N:ast_node>(&self,
             id: node.id(),
             span: node.span(),
             mutbl: base_cmt.mutbl.inherit(),
-            cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_name))),
+            cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_index, f_name))),
             ty: f_ty,
             note: NoteNone
         });
@@ -1262,7 +1278,7 @@ fn cat_pattern_<F>(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR
 
             for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
                 let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
-                let interior = InteriorField(FieldIndex(Name::intern(&i.to_string())));
+                let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
                 let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior);
                 self.cat_pattern_(subcmt, &subpat, op)?;
             }
@@ -1285,7 +1301,8 @@ fn cat_pattern_<F>(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR
 
             for fp in field_pats {
                 let field_ty = self.pat_ty(&fp.node.pat)?; // see (*2)
-                let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.name, field_ty);
+                let f_index = self.tcx.field_index(fp.node.id, self.tables);
+                let cmt_field = self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty);
                 self.cat_pattern_(cmt_field, &fp.node.pat, op)?;
             }
           }
@@ -1302,7 +1319,7 @@ fn cat_pattern_<F>(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McR
             };
             for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
                 let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
-                let interior = InteriorField(FieldIndex(Name::intern(&i.to_string())));
+                let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
                 let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior);
                 self.cat_pattern_(subcmt, &subpat, op)?;
             }
@@ -1521,7 +1538,7 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
 impl fmt::Debug for InteriorKind {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            InteriorField(FieldIndex(name)) => write!(f, "{}", name),
+            InteriorField(FieldIndex(_, info)) => write!(f, "{}", info),
             InteriorElement(..) => write!(f, "[]"),
         }
     }
index 1e5d0753e6932f463ac0ee1c5b631d58f225768f..76ec8c21743e06653118aa839bf7a741d01eb455 100644 (file)
@@ -346,6 +346,12 @@ pub struct TypeckTables<'tcx> {
     /// method calls, including those of overloaded operators.
     type_dependent_defs: ItemLocalMap<Def>,
 
+    /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
+    /// or patterns (`S { field }`). The index is often useful by itself, but to learn more
+    /// about the field you also need definition of the variant to which the field
+    /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
+    field_indices: ItemLocalMap<usize>,
+
     /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in
     /// MIR.
     user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
@@ -426,6 +432,7 @@ pub fn empty(local_id_root: Option<DefId>) -> TypeckTables<'tcx> {
         TypeckTables {
             local_id_root,
             type_dependent_defs: ItemLocalMap(),
+            field_indices: ItemLocalMap(),
             user_provided_tys: ItemLocalMap(),
             node_types: ItemLocalMap(),
             node_substs: ItemLocalMap(),
@@ -468,6 +475,20 @@ pub fn type_dependent_defs_mut(&mut self) -> LocalTableInContextMut<Def> {
         }
     }
 
+    pub fn field_indices(&self) -> LocalTableInContext<usize> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.field_indices
+        }
+    }
+
+    pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<usize> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.field_indices
+        }
+    }
+
     pub fn user_provided_tys(&self) -> LocalTableInContext<CanonicalTy<'tcx>> {
         LocalTableInContext {
             local_id_root: self.local_id_root,
@@ -706,6 +727,7 @@ fn hash_stable<W: StableHasherResult>(&self,
         let ty::TypeckTables {
             local_id_root,
             ref type_dependent_defs,
+            ref field_indices,
             ref user_provided_tys,
             ref node_types,
             ref node_substs,
@@ -726,6 +748,7 @@ fn hash_stable<W: StableHasherResult>(&self,
 
         hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
             type_dependent_defs.hash_stable(hcx, hasher);
+            field_indices.hash_stable(hcx, hasher);
             user_provided_tys.hash_stable(hcx, hasher);
             node_types.hash_stable(hcx, hasher);
             node_substs.hash_stable(hcx, hasher);
index 33b59eda7ce2ccb6ba54b27a3a3016f4e0afc7c0..d0850f5ba6e9a5f98c82a0a372d9c6a0c2f438b0 100644 (file)
@@ -50,7 +50,7 @@
 use std::mem;
 use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId};
 use syntax::attr;
-use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::ext::hygiene::Mark;
 use syntax::symbol::{Symbol, InternedString};
 use syntax_pos::{DUMMY_SP, Span};
 
@@ -2091,32 +2091,6 @@ fn sized_constraint_for_ty(&self,
     }
 }
 
-impl<'a, 'gcx, 'tcx> VariantDef {
-    #[inline]
-    pub fn find_field_named(&self, name: ast::Name) -> Option<&FieldDef> {
-        self.index_of_field_named(name).map(|index| &self.fields[index])
-    }
-
-    pub fn index_of_field_named(&self, name: ast::Name) -> Option<usize> {
-        if let Some(index) = self.fields.iter().position(|f| f.name == name) {
-            return Some(index);
-        }
-        let mut ident = name.to_ident();
-        while ident.span.ctxt() != SyntaxContext::empty() {
-            ident.span.remove_mark();
-            if let Some(field) = self.fields.iter().position(|f| f.name.to_ident() == ident) {
-                return Some(field);
-            }
-        }
-        None
-    }
-
-    #[inline]
-    pub fn field_named(&self, name: ast::Name) -> &FieldDef {
-        self.find_field_named(name).unwrap()
-    }
-}
-
 impl<'a, 'gcx, 'tcx> FieldDef {
     pub fn ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> {
         tcx.type_of(self.did).subst(tcx, subst)
@@ -2383,6 +2357,17 @@ fn associated_item_from_impl_item_ref(self,
         }
     }
 
+    pub fn field_index(self, node_id: NodeId, tables: &TypeckTables) -> usize {
+        let hir_id = self.hir.node_to_hir_id(node_id);
+        tables.field_indices().get(hir_id).cloned().expect("no index for a field")
+    }
+
+    pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> {
+        variant.fields.iter().position(|field| {
+            self.adjust_ident(ident.modern(), variant.did, DUMMY_NODE_ID).0 == field.name.to_ident()
+        })
+    }
+
     pub fn associated_items(
         self,
         def_id: DefId,
index c170c2a63e82996b697b913e67141dea58fe22bd..77eff49d19ff615d505efc553416a8e391f803cc 100644 (file)
@@ -33,7 +33,7 @@
 use std::{cmp, fmt};
 use std::hash::Hash;
 use std::intrinsics;
-use syntax::ast::{self, Name};
+use syntax::ast;
 use syntax::attr::{self, SignedInt, UnsignedInt};
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -270,42 +270,6 @@ pub fn has_error_field(self, ty: Ty<'tcx>) -> bool {
         false
     }
 
-    /// Returns the type of element at index `i` in tuple or tuple-like type `t`.
-    /// For an enum `t`, `variant` is None only if `t` is a univariant enum.
-    pub fn positional_element_ty(self,
-                                 ty: Ty<'tcx>,
-                                 i: usize,
-                                 variant: Option<DefId>) -> Option<Ty<'tcx>> {
-        match (&ty.sty, variant) {
-            (&TyAdt(adt, substs), Some(vid)) => {
-                adt.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs))
-            }
-            (&TyAdt(adt, substs), None) => {
-                // Don't use `non_enum_variant`, this may be a univariant enum.
-                adt.variants[0].fields.get(i).map(|f| f.ty(self, substs))
-            }
-            (&TyTuple(ref v), None) => v.get(i).cloned(),
-            _ => None,
-        }
-    }
-
-    /// Returns the type of element at field `n` in struct or struct-like type `t`.
-    /// For an enum `t`, `variant` must be some def id.
-    pub fn named_element_ty(self,
-                            ty: Ty<'tcx>,
-                            n: Name,
-                            variant: Option<DefId>) -> Option<Ty<'tcx>> {
-        match (&ty.sty, variant) {
-            (&TyAdt(adt, substs), Some(vid)) => {
-                adt.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs))
-            }
-            (&TyAdt(adt, substs), None) => {
-                adt.non_enum_variant().find_field_named(n).map(|f| f.ty(self, substs))
-            }
-            _ => return None
-        }
-    }
-
     /// Returns the deeply last field of nested structures, or the same type,
     /// if not a structure at all. Corresponds to the only possible unsized
     /// field, and its type can be used to determine unsizing strategy.
index 2bd40890ca3a409d66f5ed73c35491b4d124f2d6..e3adb51433b252a959c25ef1ec796f68e815bf66 100644 (file)
@@ -107,8 +107,9 @@ fn restrict(&self,
                     ty::TyAdt(adt_def, _) if adt_def.is_union() => match result {
                         RestrictionResult::Safe => RestrictionResult::Safe,
                         RestrictionResult::SafeIf(base_lp, mut base_vec) => {
-                            for field in &adt_def.non_enum_variant().fields {
-                                let field = InteriorKind::InteriorField(mc::FieldIndex(field.name));
+                            for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() {
+                                let field =
+                                    InteriorKind::InteriorField(mc::FieldIndex(i, field.name));
                                 let field_ty = if field == interior {
                                     cmt.ty
                                 } else {
index 12c5fcdf13df26dc08e595596280141e5f060541..6d832d4060a1fc7d46653a3587f5aec47e9a05b3 100644 (file)
@@ -1336,10 +1336,10 @@ pub fn append_loan_path_to_string(&self,
                 out.push(')');
             }
 
-            LpExtend(ref lp_base, _, LpInterior(_, InteriorField(mc::FieldIndex(fname)))) => {
+            LpExtend(ref lp_base, _, LpInterior(_, InteriorField(mc::FieldIndex(_, info)))) => {
                 self.append_autoderefd_loan_path_to_string(&lp_base, out);
                 out.push('.');
-                out.push_str(&fname.as_str());
+                out.push_str(&info.as_str());
             }
 
             LpExtend(ref lp_base, _, LpInterior(_, InteriorElement)) => {
@@ -1414,7 +1414,7 @@ fn initial_value(&self) -> bool {
 impl<'tcx> fmt::Debug for InteriorKind {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
-            InteriorField(mc::FieldIndex(name)) => write!(f, "{}", name),
+            InteriorField(mc::FieldIndex(_, info)) => write!(f, "{}", info),
             InteriorElement => write!(f, "[]"),
         }
     }
index a69b9dc0d4f5209f40bd58b3c2bad28846a50d35..1f4050a5b3624dd91654e261e91a6c608a392138 100644 (file)
@@ -342,8 +342,8 @@ pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
             if let (&ty::TyAdt(adt_def, _), LpInterior(opt_variant_id, interior))
                     = (&base_lp.ty.sty, lp_elem) {
                 if adt_def.is_union() {
-                    for field in &adt_def.non_enum_variant().fields {
-                        let field = InteriorKind::InteriorField(mc::FieldIndex(field.name));
+                    for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() {
+                        let field = InteriorKind::InteriorField(mc::FieldIndex(i, field.name));
                         if field != interior {
                             let sibling_lp_kind =
                                 LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
@@ -394,8 +394,8 @@ pub fn add_assignment(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
             if let ty::TyAdt(adt_def, _) = base_lp.ty.sty {
                 if adt_def.is_union() {
-                    for field in &adt_def.non_enum_variant().fields {
-                        let field = InteriorKind::InteriorField(mc::FieldIndex(field.name));
+                    for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() {
+                        let field = InteriorKind::InteriorField(mc::FieldIndex(i, field.name));
                         let field_ty = if field == interior {
                             lp.ty
                         } else {
index 48e9cc498dceb8b44ceba28e9abaf0202e8b3bd8..6f2c51b0f1899afaadaf2dcb99e6e43859819878 100644 (file)
@@ -166,19 +166,24 @@ fn get_lints(&self) -> LintArray {
 
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns {
     fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
-        if let PatKind::Struct(_, ref field_pats, _) = pat.node {
+        if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.node {
+            let variant = cx.tables.pat_ty(pat).ty_adt_def()
+                                   .expect("struct pattern type is not an ADT")
+                                   .variant_of_def(cx.tables.qpath_def(qpath, pat.hir_id));
             for fieldpat in field_pats {
                 if fieldpat.node.is_shorthand {
                     continue;
                 }
+                if fieldpat.span.ctxt().outer().expn_info().is_some() {
+                    // Don't lint if this is a macro expansion: macro authors
+                    // shouldn't have to worry about this kind of style issue
+                    // (Issue #49588)
+                    continue;
+                }
                 if let PatKind::Binding(_, _, name, None) = fieldpat.node.pat.node {
-                    if name.node == fieldpat.node.name {
-                        if let Some(_) = fieldpat.span.ctxt().outer().expn_info() {
-                            // Don't lint if this is a macro expansion: macro authors
-                            // shouldn't have to worry about this kind of style issue
-                            // (Issue #49588)
-                            return;
-                        }
+                    let binding_ident = ast::Ident::new(name.node, name.span);
+                    if cx.tcx.find_field_index(binding_ident, &variant) ==
+                       Some(cx.tcx.field_index(fieldpat.node.id, cx.tables)) {
                         let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS,
                                      fieldpat.span,
                                      &format!("the `{}:` in this pattern is redundant",
index efe88c6789ff5dbc68a3279b3efd54fa45078c16..c0d2828094695999d1b259eea6cd9c5aede7a24a 100644 (file)
@@ -16,7 +16,7 @@
 use rustc::hir::def::{Def, CtorKind};
 use rustc::middle::const_val::ConstVal;
 use rustc::mir::interpret::{GlobalId, Value, PrimVal};
-use rustc::ty::{self, AdtKind, VariantDef, Ty};
+use rustc::ty::{self, AdtKind, Ty};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::cast::CastKind as TyCastKind;
 use rustc::hir;
@@ -420,12 +420,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 ty::TyAdt(adt, substs) => {
                     match adt.adt_kind() {
                         AdtKind::Struct | AdtKind::Union => {
-                            let field_refs = field_refs(&adt.variants[0], fields);
                             ExprKind::Adt {
                                 adt_def: adt,
                                 variant_index: 0,
                                 substs,
-                                fields: field_refs,
+                                fields: field_refs(cx, fields),
                                 base: base.as_ref().map(|base| {
                                     FruInfo {
                                         base: base.to_ref(),
@@ -446,12 +445,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                     assert!(base.is_none());
 
                                     let index = adt.variant_index_with_id(variant_id);
-                                    let field_refs = field_refs(&adt.variants[index], fields);
                                     ExprKind::Adt {
                                         adt_def: adt,
                                         variant_index: index,
                                         substs,
-                                        fields: field_refs,
+                                        fields: field_refs(cx, fields),
                                         base: None,
                                     }
                                 }
@@ -581,19 +579,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 body: block::to_expr_ref(cx, body),
             }
         }
-        hir::ExprField(ref source, name) => {
-            let index = match cx.tables().expr_ty_adjusted(source).sty {
-                ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node),
-                ty::TyTuple(..) => name.node.as_str().parse::<usize>().ok(),
-                ref ty => span_bug!(expr.span, "field of non-ADT: {:?}", ty),
-            };
-            let index =
-                index.unwrap_or_else(|| {
-                    span_bug!(expr.span, "no index found for field `{}`", name.node)
-                });
+        hir::ExprField(ref source, ..) => {
             ExprKind::Field {
                 lhs: source.to_ref(),
-                name: Field::new(index),
+                name: Field::new(cx.tcx.field_index(expr.id, cx.tables)),
             }
         }
         hir::ExprCast(ref source, _) => {
@@ -994,13 +983,13 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 }
 
 /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef.
-fn field_refs<'tcx>(variant: &'tcx VariantDef,
-                    fields: &'tcx [hir::Field])
-                    -> Vec<FieldExprRef<'tcx>> {
+fn field_refs<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
+                              fields: &'tcx [hir::Field])
+                              -> Vec<FieldExprRef<'tcx>> {
     fields.iter()
         .map(|field| {
             FieldExprRef {
-                name: Field::new(variant.index_of_field_named(field.name.node).unwrap()),
+                name: Field::new(cx.tcx.field_index(field.id, cx.tables)),
                 expr: field.expr.to_ref(),
             }
         })
index c3f41e8ac4827f5970fb9e11dfab2c2f7db695ab..8d2b73d6ba033842693aa3dd6827c1575864e8e5 100644 (file)
@@ -528,28 +528,12 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
 
             PatKind::Struct(ref qpath, ref fields, _) => {
                 let def = self.tables.qpath_def(qpath, pat.hir_id);
-                let adt_def = match ty.sty {
-                    ty::TyAdt(adt_def, _) => adt_def,
-                    _ => {
-                        span_bug!(
-                            pat.span,
-                            "struct pattern not applied to an ADT");
-                    }
-                };
-                let variant_def = adt_def.variant_of_def(def);
-
                 let subpatterns =
                     fields.iter()
                           .map(|field| {
-                              let index = variant_def.index_of_field_named(field.node.name);
-                              let index = index.unwrap_or_else(|| {
-                                  span_bug!(
-                                      pat.span,
-                                      "no field with name {:?}",
-                                      field.node.name);
-                              });
                               FieldPattern {
-                                  field: Field::new(index),
+                                  field: Field::new(self.tcx.field_index(field.node.id,
+                                                                         self.tables)),
                                   pattern: self.lower_pattern(&field.node.pat),
                               }
                           })
index ef710ff7a7e4b6447775f404c25a39ac7040900d..ee08e6223903e39e9079c332d73189d08072c947 100644 (file)
@@ -568,8 +568,10 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
                     // If the expression uses FRU we need to make sure all the unmentioned fields
                     // are checked for privacy (RFC 736). Rather than computing the set of
                     // unmentioned fields, just check them all.
-                    for variant_field in &variant.fields {
-                        let field = fields.iter().find(|f| f.name.node == variant_field.name);
+                    for (vf_index, variant_field) in variant.fields.iter().enumerate() {
+                        let field = fields.iter().find(|f| {
+                            self.tcx.field_index(f.id, self.tables) == vf_index
+                        });
                         let (use_ctxt, span) = match field {
                             Some(field) => (field.name.node.to_ident().span, field.span),
                             None => (base.span, base.span),
@@ -579,8 +581,8 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
                 } else {
                     for field in fields {
                         let use_ctxt = field.name.node.to_ident().span;
-                        let field_def = variant.field_named(field.name.node);
-                        self.check_field(use_ctxt, field.span, adt, field_def);
+                        let index = self.tcx.field_index(field.id, self.tables);
+                        self.check_field(use_ctxt, field.span, adt, &variant.fields[index]);
                     }
                 }
             }
@@ -598,8 +600,8 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
                 let variant = adt.variant_of_def(def);
                 for field in fields {
                     let use_ctxt = field.node.name.to_ident().span;
-                    let field_def = variant.field_named(field.node.name);
-                    self.check_field(use_ctxt, field.span, adt, field_def);
+                    let index = self.tcx.field_index(field.node.id, self.tables);
+                    self.check_field(use_ctxt, field.span, adt, &variant.fields[index]);
                 }
             }
             _ => {}
index 811ebe576694971810b876e76a48d2e386164b25..abaa02a856e9cae181944eda5a8fed471205c308 100644 (file)
@@ -1005,20 +1005,16 @@ fn process_pat(&mut self, p: &'l ast::Pat) {
                 };
                 let variant = adt.variant_of_def(self.save_ctxt.get_path_def(p.id));
 
-                for &Spanned {
-                    node: ref field,
-                    span,
-                } in fields
-                {
+                for &Spanned { node: ref field, span } in fields {
                     let sub_span = self.span.span_for_first_ident(span);
-                    if let Some(f) = variant.find_field_named(field.ident.name) {
+                    if let Some(index) = self.tcx.find_field_index(field.ident, variant) {
                         if !self.span.filter_generated(sub_span, span) {
                             let span =
                                 self.span_from_span(sub_span.expect("No span fund for var ref"));
                             self.dumper.dump_ref(Ref {
                                 kind: RefKind::Variable,
                                 span,
-                                ref_id: ::id_from_def_id(f.did),
+                                ref_id: ::id_from_def_id(variant.fields[index].did),
                             });
                         }
                     }
index 9da692851d9d830375c23009a2d65791602359da..ca19ed0df67d1ab9efa4657867dff7a861d844e3 100644 (file)
@@ -553,14 +553,15 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
                 };
                 match self.tables.expr_ty_adjusted(&hir_node).sty {
                     ty::TyAdt(def, _) if !def.is_enum() => {
-                        let f = def.non_enum_variant().field_named(ident.name);
+                        let variant = &def.non_enum_variant();
+                        let index = self.tcx.find_field_index(ident, variant).unwrap();
                         let sub_span = self.span_utils.span_for_last_ident(expr.span);
                         filter!(self.span_utils, sub_span, expr.span, None);
                         let span = self.span_from_span(sub_span.unwrap());
                         return Some(Data::RefData(Ref {
                             kind: RefKind::Variable,
                             span,
-                            ref_id: id_from_def_id(f.did),
+                            ref_id: id_from_def_id(variant.fields[index].did),
                         }));
                     }
                     ty::TyTuple(..) => None,
@@ -817,7 +818,7 @@ pub fn get_field_ref_data(
         field_ref: &ast::Field,
         variant: &ty::VariantDef,
     ) -> Option<Ref> {
-        let f = variant.find_field_named(field_ref.ident.name)?;
+        let index = self.tcx.find_field_index(field_ref.ident, variant).unwrap();
         // We don't really need a sub-span here, but no harm done
         let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
         filter!(self.span_utils, sub_span, field_ref.ident.span, None);
@@ -825,7 +826,7 @@ pub fn get_field_ref_data(
         Some(Ref {
             kind: RefKind::Variable,
             span,
-            ref_id: id_from_def_id(f.did),
+            ref_id: id_from_def_id(variant.fields[index].did),
         })
     }
 
index ae373fbad22465cc034cc68c644883cdd2ab99ea..7b4dc60409b122b89cc35d2702795ab349784c6c 100644 (file)
@@ -860,7 +860,8 @@ fn check_struct_pat_fields(&self,
         // Index the struct fields' types.
         let field_map = variant.fields
             .iter()
-            .map(|field| (field.name, field))
+            .enumerate()
+            .map(|(i, field)| (field.name.to_ident(), (i, field)))
             .collect::<FxHashMap<_, _>>();
 
         // Keep track of which fields have already appeared in the pattern.
@@ -869,7 +870,8 @@ fn check_struct_pat_fields(&self,
         let mut inexistent_fields = vec![];
         // Typecheck each field.
         for &Spanned { node: ref field, span } in fields {
-            let field_ty = match used_fields.entry(field.name) {
+            let ident = tcx.adjust(field.name, variant.did, self.body_id).0;
+            let field_ty = match used_fields.entry(ident) {
                 Occupied(occupied) => {
                     struct_span_err!(tcx.sess, span, E0025,
                                      "field `{}` bound multiple times \
@@ -883,10 +885,10 @@ fn check_struct_pat_fields(&self,
                 }
                 Vacant(vacant) => {
                     vacant.insert(span);
-                    field_map.get(&field.name)
-                        .map(|f| {
+                    field_map.get(&ident)
+                        .map(|(i, f)| {
+                            self.write_field_index(field.id, *i);
                             self.tcx.check_stability(f.did, Some(pat_id), span);
-
                             self.field_ty(span, f, substs)
                         })
                         .unwrap_or_else(|| {
@@ -958,8 +960,8 @@ fn check_struct_pat_fields(&self,
         } else if !etc {
             let unmentioned_fields = variant.fields
                 .iter()
-                .map(|field| field.name)
-                .filter(|field| !used_fields.contains_key(&field))
+                .map(|field| field.name.to_ident())
+                .filter(|ident| !used_fields.contains_key(&ident))
                 .collect::<Vec<_>>();
             if unmentioned_fields.len() > 0 {
                 let field_names = if unmentioned_fields.len() == 1 {
index 2dbc590bbf72748ff8652decfaadfee6cd5fc721..d8907866467ba0b0478cd0390cae8223628ee371 100644 (file)
@@ -304,8 +304,10 @@ pub fn report_method_error(&self,
                     for (ty, _) in self.autoderef(span, rcvr_ty) {
                         match ty.sty {
                             ty::TyAdt(def, substs) if !def.is_enum() => {
-                                if let Some(field) = def.non_enum_variant()
-                                    .find_field_named(item_name) {
+                                let variant = &def.non_enum_variant();
+                                if let Some(index) =
+                                        self.tcx.find_field_index(item_name.to_ident(), variant) {
+                                    let field = &variant.fields[index];
                                     let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
                                     let expr_string = match snippet {
                                         Ok(expr_string) => expr_string,
index 9d0e0191ffba3bd81c13cde586884b714adacd32..ca35153d571dbd0048cf8ada21af03d6d5832a04 100644 (file)
@@ -1938,6 +1938,11 @@ pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
         }
     }
 
+    pub fn write_field_index(&self, node_id: ast::NodeId, index: usize) {
+        let hir_id = self.tcx.hir.node_to_hir_id(node_id);
+        self.tables.borrow_mut().field_indices_mut().insert(hir_id, index);
+    }
+
     // The NodeId and the ItemLocalId must identify the same item. We just pass
     // both of them for consistency checking.
     pub fn write_method_call(&self,
@@ -3069,15 +3074,16 @@ fn check_field(&self,
                     let (ident, def_scope) =
                         self.tcx.adjust(field.node, base_def.did, self.body_id);
                     let fields = &base_def.non_enum_variant().fields;
-                    if let Some(field) = fields.iter().find(|f| f.name.to_ident() == ident) {
+                    if let Some(index) = fields.iter().position(|f| f.name.to_ident() == ident) {
+                        let field = &fields[index];
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
                             let adjustments = autoderef.adjust_steps(needs);
                             self.apply_adjustments(base, adjustments);
                             autoderef.finalize();
 
+                            self.write_field_index(expr.id, index);
                             self.tcx.check_stability(field.did, Some(expr.id), expr.span);
-
                             return field_ty;
                         }
                         private_candidate = Some((base_def.did, field_ty));
@@ -3092,6 +3098,7 @@ fn check_field(&self,
                                 self.apply_adjustments(base, adjustments);
                                 autoderef.finalize();
 
+                                self.write_field_index(expr.id, index);
                                 return field_ty;
                             }
                         }
@@ -3284,8 +3291,8 @@ fn check_expr_struct_fields(&self,
         };
 
         let mut remaining_fields = FxHashMap();
-        for field in &variant.fields {
-            remaining_fields.insert(field.name.to_ident(), field);
+        for (i, field) in variant.fields.iter().enumerate() {
+            remaining_fields.insert(field.name.to_ident(), (i, field));
         }
 
         let mut seen_fields = FxHashMap();
@@ -3295,8 +3302,9 @@ fn check_expr_struct_fields(&self,
         // Typecheck each field.
         for field in ast_fields {
             let ident = tcx.adjust(field.name.node, variant.did, self.body_id).0;
-            let field_type = if let Some(v_field) = remaining_fields.remove(&ident) {
-                seen_fields.insert(field.name.node, field.span);
+            let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
+                seen_fields.insert(ident, field.span);
+                self.write_field_index(field.id, i);
 
                 // we don't look at stability attributes on
                 // struct-like enums (yet...), but it's definitely not
@@ -3308,18 +3316,15 @@ fn check_expr_struct_fields(&self,
                 self.field_ty(field.span, v_field, substs)
             } else {
                 error_happened = true;
-                if let Some(_) = variant.find_field_named(field.name.node) {
+                if let Some(prev_span) = seen_fields.get(&ident) {
                     let mut err = struct_span_err!(self.tcx.sess,
                                                 field.name.span,
                                                 E0062,
                                                 "field `{}` specified more than once",
-                                                field.name.node);
+                                                ident);
 
                     err.span_label(field.name.span, "used more than once");
-
-                    if let Some(prev_span) = seen_fields.get(&field.name.node) {
-                        err.span_label(*prev_span, format!("first use of `{}`", field.name.node));
-                    }
+                    err.span_label(*prev_span, format!("first use of `{}`", ident));
 
                     err.emit();
                 } else {
index bbd04e0b19ae194a3e9365bf2df24d1437aa88dd..6e0d7dd8508775719988da59e7af640fbdb57bac 100644 (file)
@@ -226,13 +226,24 @@ fn visit_expr(&mut self, e: &'gcx hir::Expr) {
 
         self.visit_node_id(e.span, e.hir_id);
 
-        if let hir::ExprClosure(_, _, body, _, _) = e.node {
-            let body = self.fcx.tcx.hir.body(body);
-            for arg in &body.arguments {
-                self.visit_node_id(e.span, arg.hir_id);
-            }
+        match e.node {
+            hir::ExprClosure(_, _, body, _, _) => {
+                let body = self.fcx.tcx.hir.body(body);
+                for arg in &body.arguments {
+                    self.visit_node_id(e.span, arg.hir_id);
+                }
 
-            self.visit_body(body);
+                self.visit_body(body);
+            }
+            hir::ExprStruct(_, ref fields, _) => {
+                for field in fields {
+                    self.visit_field_id(field.id);
+                }
+            }
+            hir::ExprField(..) => {
+                self.visit_field_id(e.id);
+            }
+            _ => {}
         }
 
         intravisit::walk_expr(self, e);
@@ -254,6 +265,11 @@ fn visit_pat(&mut self, p: &'gcx hir::Pat) {
                     .expect("missing binding mode");
                 self.tables.pat_binding_modes_mut().insert(p.hir_id, bm);
             }
+            hir::PatKind::Struct(_, ref fields, _) => {
+                for field in fields {
+                    self.visit_field_id(field.node.id);
+                }
+            }
             _ => {}
         };
 
@@ -384,6 +400,13 @@ fn visit_anon_types(&mut self) {
         }
     }
 
+    fn visit_field_id(&mut self, node_id: ast::NodeId) {
+        let hir_id = self.tcx().hir.node_to_hir_id(node_id);
+        if let Some(index) = self.fcx.tables.borrow_mut().field_indices_mut().remove(hir_id) {
+            self.tables.field_indices_mut().insert(hir_id, index);
+        }
+    }
+
     fn visit_node_id(&mut self, span: Span, hir_id: hir::HirId) {
         // Export associated path extensions and method resultions.
         if let Some(def) = self.fcx
index a4f820d1fdcf9553488b85b9da013929f9307f47..640e6488862788d1a90e1106166f7e5e7bc3e204 100644 (file)
@@ -513,11 +513,11 @@ fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     discr: ty::VariantDiscr,
                                     def: &hir::VariantData)
                                     -> ty::VariantDef {
-    let mut seen_fields: FxHashMap<ast::Name, Span> = FxHashMap();
+    let mut seen_fields: FxHashMap<ast::Ident, Span> = FxHashMap();
     let node_id = tcx.hir.as_local_node_id(did).unwrap();
     let fields = def.fields().iter().map(|f| {
         let fid = tcx.hir.local_def_id(f.id);
-        let dup_span = seen_fields.get(&f.name).cloned();
+        let dup_span = seen_fields.get(&f.name.to_ident()).cloned();
         if let Some(prev_span) = dup_span {
             struct_span_err!(tcx.sess, f.span, E0124,
                              "field `{}` is already declared",
@@ -526,7 +526,7 @@ fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 .span_label(prev_span, format!("`{}` first declared here", f.name))
                 .emit();
         } else {
-            seen_fields.insert(f.name, f.span);
+            seen_fields.insert(f.name.to_ident(), f.span);
         }
 
         ty::FieldDef {
index 2e1a4ee5851572df0a946b7fd177dbbb797da394..36244f0a3c43874df3b5f637be258a43ac155f0b 100644 (file)
@@ -636,8 +636,8 @@ fn expr_field_access(&self, sp: Span, expr: P<ast::Expr>, ident: ast::Ident) ->
         self.expr(sp, ast::ExprKind::Field(expr, ident.with_span_pos(sp)))
     }
     fn expr_tup_field_access(&self, sp: Span, expr: P<ast::Expr>, idx: usize) -> P<ast::Expr> {
-        let id = Spanned { node: Ident::from_str(&idx.to_string()), span: sp };
-        self.expr(sp, ast::ExprKind::Field(expr, id))
+        let ident = Ident::from_str(&idx.to_string()).with_span_pos(sp);
+        self.expr(sp, ast::ExprKind::Field(expr, ident))
     }
     fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
         self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Immutable, e))
index 33a602a26fcf75f533f25921878cedcc2e44487c..a7a9ce745122c36612eecdbf51ffc331cf1e16e6 100644 (file)
@@ -2604,8 +2604,7 @@ fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a,
                   token::Literal(token::Integer(name), _) => {
                     let span = self.span;
                     self.bump();
-                    let ident = Ident { name, ctxt: span.ctxt() };
-                    let field = ExprKind::Field(e, respan(span, ident));
+                    let field = ExprKind::Field(e, Ident::new(name, span));
                     e = self.mk_expr(lo.to(span), field, ThinVec::new());
                   }
                   token::Literal(token::Float(n), _suf) => {
@@ -7031,7 +7030,7 @@ fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
             match self.token {
                 token::Ident(ident, false) if ident.name == keywords::Underscore.name() => {
                     self.bump(); // `_`
-                    Ok(Some(Ident { name: ident.name.gensymed(), ..ident }))
+                    Ok(Some(Ident::new(ident.name.gensymed(), ident.span)))
                 }
                 _ => self.parse_ident().map(Some),
             }
index a214e3c126e8d7af538bae7f4afd9f6a9cf01d08..eec7df84c82f7f8eced3cbb13bece589cece0891 100644 (file)
@@ -36,7 +36,7 @@ fn main() {
 
     let mut line1 = Line::default();
     let _moved = line1.origin;
-    let _ = line1.origin.x + 1; //[ast]~ ERROR use of collaterally moved value: `line1.origin.x`
+    let _ = line1.origin.x + 1; //[ast]~ ERROR use of moved value: `line1.origin.x`
                                 //[mir]~^ [E0382]
 
     let mut line2 = Line::default();