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:
parent
44acea4d88
commit
4f69b7fb85
27 changed files with 244 additions and 226 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, "[]"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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, "[]"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -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),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue