1
Fork 0

Avoid comparing fields by name when possible

Resolve them into field indices once and then use those resolutions

+ Fix rebase
This commit is contained in:
Vadim Petrochenkov 2018-04-05 03:20:21 +03:00
parent 44acea4d88
commit 4f69b7fb85
27 changed files with 244 additions and 226 deletions

View 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)
}

View file

@ -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<hir::Expr>, span: Span) -> hir::Field {
hir::Field {
id: self.next_id().node_id,
name: Spanned { node: name, span },
span,
expr,

View file

@ -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<Name>,
pub expr: P<Expr>,
pub span: Span,

View file

@ -420,11 +420,23 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Pat {
}
impl_stable_hash_for_spanned!(hir::FieldPat);
impl_stable_hash_for!(struct hir::FieldPat {
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,
pat,
is_shorthand
});
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 {
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,
expr,
ref expr,
span,
is_shorthand
});
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);

View 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 @@ 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<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 @@ 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);
}
}
_ => ()

View file

@ -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

View file

@ -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<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 @@ 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<ImmutabilityBlame<'tcx>> {
@ -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<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 @@ 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, "[]"),
}
}

View 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 @@ 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<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 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> 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<StableHashingContext<'a>> 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);

View file

@ -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<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 @@ 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<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,

View file

@ -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<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.

View file

@ -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 {

View file

@ -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, "[]"),
}
}

View file

@ -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 {

View file

@ -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 let PatKind::Binding(_, _, name, None) = fieldpat.node.pat.node {
if name.node == fieldpat.node.name {
if let Some(_) = fieldpat.span.ctxt().outer().expn_info() {
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)
return;
continue;
}
if let PatKind::Binding(_, _, name, None) = fieldpat.node.pat.node {
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",

View file

@ -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::<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,
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(),
}
})

View file

@ -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),
}
})

View file

@ -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]);
}
}
_ => {}

View file

@ -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),
});
}
}

View file

@ -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<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 @@ 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),
})
}

View file

@ -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::<FxHashMap<_, _>>();
// 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::<Vec<_>>();
if unmentioned_fields.len() > 0 {
let field_names = if unmentioned_fields.len() == 1 {

View file

@ -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,

View file

@ -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 {

View file

@ -226,7 +226,8 @@ 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 {
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);
@ -234,6 +235,16 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
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

View 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 {

View file

@ -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<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))

View file

@ -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),
}

View 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();