From 44acea4d880b646caa00a7237ea1a17031dd2116 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 1 Apr 2018 21:48:39 +0300 Subject: AST/HIR: Merge field access expressions for named and numeric fields --- src/libsyntax/parse/parser.rs | 37 +++++-------------------------------- 1 file changed, 5 insertions(+), 32 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 027b24cbbdc..33a602a26fc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2144,10 +2144,6 @@ impl<'a> Parser<'a> { } } - pub fn mk_tup_field(&mut self, expr: P, idx: codemap::Spanned) -> ast::ExprKind { - ExprKind::TupField(expr, idx) - } - pub fn mk_assign_op(&mut self, binop: ast::BinOp, lhs: P, rhs: P) -> ast::ExprKind { ExprKind::AssignOp(binop, lhs, rhs) @@ -2605,35 +2601,12 @@ impl<'a> Parser<'a> { token::Ident(..) => { e = self.parse_dot_suffix(e, lo)?; } - token::Literal(token::Integer(index_ident), suf) => { - let sp = self.span; - - // A tuple index may not have a suffix - self.expect_no_suffix(sp, "tuple index", suf); - - let idx_span = self.span; + token::Literal(token::Integer(name), _) => { + let span = self.span; self.bump(); - - let invalid_msg = "invalid tuple or struct index"; - - let index = index_ident.as_str().parse::().ok(); - match index { - Some(n) => { - if n.to_string() != index_ident.as_str() { - let mut err = self.struct_span_err(self.prev_span, invalid_msg); - err.span_suggestion(self.prev_span, - "try simplifying the index", - n.to_string()); - err.emit(); - } - let field = self.mk_tup_field(e, respan(idx_span, n)); - e = self.mk_expr(lo.to(idx_span), field, ThinVec::new()); - } - None => { - let prev_span = self.prev_span; - self.span_err(prev_span, invalid_msg); - } - } + let ident = Ident { name, ctxt: span.ctxt() }; + let field = ExprKind::Field(e, respan(span, ident)); + e = self.mk_expr(lo.to(span), field, ThinVec::new()); } token::Literal(token::Float(n), _suf) => { self.bump(); -- cgit 1.4.1-3-g733a5 From 4f69b7fb850cae83ea3d5adfeb8520418c976403 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 5 Apr 2018 03:20:21 +0300 Subject: Avoid comparing fields by name when possible Resolve them into field indices once and then use those resolutions + Fix rebase --- src/librustc/hir/intravisit.rs | 2 + src/librustc/hir/lowering.rs | 3 ++ src/librustc/hir/mod.rs | 2 + src/librustc/ich/impls_hir.rs | 46 ++++++++++++++++------ src/librustc/middle/dead.rs | 37 +++++++---------- src/librustc/middle/expr_use_visitor.rs | 16 +++----- src/librustc/middle/mem_categorization.rs | 39 ++++++++++++------ src/librustc/ty/context.rs | 23 +++++++++++ src/librustc/ty/mod.rs | 39 ++++++------------ src/librustc/ty/util.rs | 38 +----------------- .../borrowck/gather_loans/restrictions.rs | 5 ++- src/librustc_borrowck/borrowck/mod.rs | 6 +-- src/librustc_borrowck/borrowck/move_data.rs | 8 ++-- src/librustc_lint/builtin.rs | 21 ++++++---- src/librustc_mir/hair/cx/expr.rs | 29 +++++--------- src/librustc_mir/hair/pattern/mod.rs | 20 +--------- src/librustc_privacy/lib.rs | 14 ++++--- src/librustc_save_analysis/dump_visitor.rs | 10 ++--- src/librustc_save_analysis/lib.rs | 9 +++-- src/librustc_typeck/check/_match.rs | 16 ++++---- src/librustc_typeck/check/method/suggest.rs | 6 ++- src/librustc_typeck/check/mod.rs | 29 ++++++++------ src/librustc_typeck/check/writeback.rs | 35 +++++++++++++--- src/librustc_typeck/collect.rs | 6 +-- src/libsyntax/ext/build.rs | 4 +- src/libsyntax/parse/parser.rs | 5 +-- .../borrowck/borrowck-uninit-field-access.rs | 2 +- 27 files changed, 244 insertions(+), 226 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 0a7f0e4dc4c..be9f8b8dac5 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -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) } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 262c307feed..fee076acb20 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2100,6 +2100,7 @@ impl<'a> LoweringContext<'a> { 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 @@ impl<'a> LoweringContext<'a> { .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 @@ impl<'a> LoweringContext<'a> { fn field(&mut self, name: Name, expr: P, span: Span) -> hir::Field { hir::Field { + id: self.next_id().node_id, name: Spanned { node: name, span }, span, expr, diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 79b39be3eb2..e6080fad91d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -827,6 +827,7 @@ impl Pat { /// 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, pub expr: P, pub span: Span, diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index ec573e3d681..4a001802eac 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -420,11 +420,23 @@ impl<'a> HashStable> for hir::Pat { } impl_stable_hash_for_spanned!(hir::FieldPat); -impl_stable_hash_for!(struct hir::FieldPat { - name, - pat, - is_shorthand -}); + +impl<'a> HashStable> for hir::FieldPat { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + 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 @@ impl_stable_hash_for!(struct hir::Arm { body }); -impl_stable_hash_for!(struct hir::Field { - name, - expr, - span, - is_shorthand -}); +impl<'a> HashStable> for hir::Field { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + 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); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 5800988344a..9ec3d2e2460 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -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 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { 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 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { self.inherited_pub_visibility = had_inherited_pub_visibility; } - fn mark_as_used_if_union(&mut self, did: DefId, fields: &hir::HirVec) { - 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) { + 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 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { 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); } } _ => () diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index fb83e563ffc..2cc5a4a8fe6 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -659,11 +659,15 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // 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 diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c7449325f75..6f41f07dce8 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -84,6 +84,7 @@ use syntax::ast::{self, Name}; 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(&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 @@ impl<'tcx> cmt_<'tcx> { &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> { @@ -639,7 +653,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn cat_field(&self, node: &N, base_cmt: cmt<'tcx>, + f_index: usize, f_name: Name, f_ty: Ty<'tcx>) -> cmt<'tcx> { @@ -974,7 +990,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; 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, "[]"), } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 1e5d0753e69..76ec8c21743 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -346,6 +346,12 @@ pub struct TypeckTables<'tcx> { /// method calls, including those of overloaded operators. type_dependent_defs: ItemLocalMap, + /// 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, + /// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in /// MIR. user_provided_tys: ItemLocalMap>, @@ -426,6 +432,7 @@ impl<'tcx> 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 @@ impl<'tcx> TypeckTables<'tcx> { } } + pub fn field_indices(&self) -> LocalTableInContext { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.field_indices + } + } + + pub fn field_indices_mut(&mut self) -> LocalTableInContextMut { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.field_indices + } + } + pub fn user_provided_tys(&self) -> LocalTableInContext> { LocalTableInContext { local_id_root: self.local_id_root, @@ -706,6 +727,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { 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 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { 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); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 33b59eda7ce..d0850f5ba6e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -50,7 +50,7 @@ use std::vec::IntoIter; 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 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } -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 { - 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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + 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 { + 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, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c170c2a63e8..77eff49d19f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -33,7 +33,7 @@ use rustc_data_structures::fx::FxHashMap; 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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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) -> Option> { - 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) -> Option> { - 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. diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 2bd40890ca3..e3adb51433b 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -107,8 +107,9 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { 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 { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 12c5fcdf13d..6d832d4060a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1336,10 +1336,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { 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 @@ impl DataFlowOperator for LoanDataFlowOperator { 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, "[]"), } } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index a69b9dc0d4f..1f4050a5b36 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -342,8 +342,8 @@ impl<'a, 'tcx> MoveData<'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 @@ impl<'a, 'tcx> MoveData<'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 { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 48e9cc498dc..6f2c51b0f18 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -166,19 +166,24 @@ impl LintPass for NonShorthandFieldPatterns { 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", diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index efe88c6789f..c0d28280946 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -16,7 +16,7 @@ use hair::cx::to_ref::ToRef; 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::().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> { +fn field_refs<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, + fields: &'tcx [hir::Field]) + -> Vec> { 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(), } }) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index c3f41e8ac48..8d2b73d6ba0 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -528,28 +528,12 @@ impl<'a, 'tcx> PatternContext<'a, '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), } }) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ef710ff7a7e..ee08e622390 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -568,8 +568,10 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { } 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 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { 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]); } } _ => {} diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 811ebe57669..abaa02a856e 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1005,20 +1005,16 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { }; 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), }); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 9da692851d9..ca19ed0df67 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -553,14 +553,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }; 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 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { field_ref: &ast::Field, variant: &ty::VariantDef, ) -> Option { - 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 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(Ref { kind: RefKind::Variable, span, - ref_id: id_from_def_id(f.did), + ref_id: id_from_def_id(variant.fields[index].did), }) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index ae373fbad22..7b4dc60409b 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -860,7 +860,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); // 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::>(); // Keep track of which fields have already appeared in the pattern. @@ -869,7 +870,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); 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 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } 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 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); } 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::>(); if unmentioned_fields.len() > 0 { let field_names = if unmentioned_fields.len() == 1 { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 2dbc590bbf7..d8907866467 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -304,8 +304,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9d0e0191ffb..ca35153d571 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1938,6 +1938,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.apply_adjustments(base, adjustments); autoderef.finalize(); + self.write_field_index(expr.id, index); return field_ty; } } @@ -3284,8 +3291,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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 { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index bbd04e0b19a..6e0d7dd8508 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -226,13 +226,24 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { 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 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { .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 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } + 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 diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a4f820d1fdc..640e6488862 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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 = FxHashMap(); + let mut seen_fields: FxHashMap = 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 { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 2e1a4ee5851..36244f0a3c4 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -636,8 +636,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(sp, ast::ExprKind::Field(expr, ident.with_span_pos(sp))) } fn expr_tup_field_access(&self, sp: Span, expr: P, idx: usize) -> P { - 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) -> P { self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Immutable, e)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 33a602a26fc..a7a9ce74512 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2604,8 +2604,7 @@ impl<'a> Parser<'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 @@ impl<'a> Parser<'a> { 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), } diff --git a/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs index a214e3c126e..eec7df84c82 100644 --- a/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs +++ b/src/test/compile-fail/borrowck/borrowck-uninit-field-access.rs @@ -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(); -- cgit 1.4.1-3-g733a5