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)
}
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)
}
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,
.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,
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,
/// 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
#[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,
}
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,
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);
// 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;
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"),
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);
}
}
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);
}
}
}
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);
}
}
_ => ()
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)
);
// 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
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;
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 {
}
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,
&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>> {
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, _) => {
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> {
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
});
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)?;
}
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)?;
}
}
};
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)?;
}
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, "[]"),
}
}
/// 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>>,
TypeckTables {
local_id_root,
type_dependent_defs: ItemLocalMap(),
+ field_indices: ItemLocalMap(),
user_provided_tys: ItemLocalMap(),
node_types: ItemLocalMap(),
node_substs: ItemLocalMap(),
}
}
+ 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,
let ty::TypeckTables {
local_id_root,
ref type_dependent_defs,
+ ref field_indices,
ref user_provided_tys,
ref node_types,
ref node_substs,
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);
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};
}
}
-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)
}
}
+ 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,
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};
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.
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 {
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)) => {
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, "[]"),
}
}
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));
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 {
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",
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;
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(),
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,
}
}
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, _) => {
}
/// 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(),
}
})
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),
}
})
// 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),
} 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]);
}
}
}
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]);
}
}
_ => {}
};
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),
});
}
}
};
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,
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);
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 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.
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 \
}
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(|| {
} 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 {
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,
}
}
+ 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,
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));
self.apply_adjustments(base, adjustments);
autoderef.finalize();
+ self.write_field_index(expr.id, index);
return field_ty;
}
}
};
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();
// 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
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 {
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);
.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);
+ }
+ }
_ => {}
};
}
}
+ 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
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",
.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 {
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))
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) => {
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),
}
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();