Skip to content

Commit 4f69b7f

Browse files
committed
Avoid comparing fields by name when possible
Resolve them into field indices once and then use those resolutions + Fix rebase
1 parent 44acea4 commit 4f69b7f

File tree

27 files changed

+244
-226
lines changed

27 files changed

+244
-226
lines changed

src/librustc/hir/intravisit.rs

+2
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
658658
PatKind::Struct(ref qpath, ref fields, _) => {
659659
visitor.visit_qpath(qpath, pattern.id, pattern.span);
660660
for field in fields {
661+
visitor.visit_id(field.node.id);
661662
visitor.visit_name(field.span, field.node.name);
662663
visitor.visit_pat(&field.node.pat)
663664
}
@@ -959,6 +960,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
959960
ExprStruct(ref qpath, ref fields, ref optional_base) => {
960961
visitor.visit_qpath(qpath, expression.id, expression.span);
961962
for field in fields {
963+
visitor.visit_id(field.id);
962964
visitor.visit_name(field.name.span, field.name.node);
963965
visitor.visit_expr(&field.expr)
964966
}

src/librustc/hir/lowering.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2100,6 +2100,7 @@ impl<'a> LoweringContext<'a> {
21002100

21012101
fn lower_field(&mut self, f: &Field) -> hir::Field {
21022102
hir::Field {
2103+
id: self.next_id().node_id,
21032104
name: respan(f.ident.span, self.lower_ident(f.ident)),
21042105
expr: P(self.lower_expr(&f.expr)),
21052106
span: f.span,
@@ -2863,6 +2864,7 @@ impl<'a> LoweringContext<'a> {
28632864
.map(|f| Spanned {
28642865
span: f.span,
28652866
node: hir::FieldPat {
2867+
id: self.next_id().node_id,
28662868
name: self.lower_ident(f.node.ident),
28672869
pat: self.lower_pat(&f.node.pat),
28682870
is_shorthand: f.node.is_shorthand,
@@ -3741,6 +3743,7 @@ impl<'a> LoweringContext<'a> {
37413743

37423744
fn field(&mut self, name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field {
37433745
hir::Field {
3746+
id: self.next_id().node_id,
37443747
name: Spanned { node: name, span },
37453748
span,
37463749
expr,

src/librustc/hir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,7 @@ impl Pat {
827827
/// except is_shorthand is true
828828
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
829829
pub struct FieldPat {
830+
pub id: NodeId,
830831
/// The identifier for the field
831832
pub name: Name,
832833
/// The pattern the field is destructured to
@@ -1172,6 +1173,7 @@ pub struct Arm {
11721173

11731174
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
11741175
pub struct Field {
1176+
pub id: NodeId,
11751177
pub name: Spanned<Name>,
11761178
pub expr: P<Expr>,
11771179
pub span: Span,

src/librustc/ich/impls_hir.rs

+35-11
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,23 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Pat {
420420
}
421421

422422
impl_stable_hash_for_spanned!(hir::FieldPat);
423-
impl_stable_hash_for!(struct hir::FieldPat {
424-
name,
425-
pat,
426-
is_shorthand
427-
});
423+
424+
impl<'a> HashStable<StableHashingContext<'a>> for hir::FieldPat {
425+
fn hash_stable<W: StableHasherResult>(&self,
426+
hcx: &mut StableHashingContext<'a>,
427+
hasher: &mut StableHasher<W>) {
428+
let hir::FieldPat {
429+
id: _,
430+
name,
431+
ref pat,
432+
is_shorthand,
433+
} = *self;
434+
435+
name.hash_stable(hcx, hasher);
436+
pat.hash_stable(hcx, hasher);
437+
is_shorthand.hash_stable(hcx, hasher);
438+
}
439+
}
428440

429441
impl_stable_hash_for!(enum hir::BindingAnnotation {
430442
Unannotated,
@@ -507,12 +519,24 @@ impl_stable_hash_for!(struct hir::Arm {
507519
body
508520
});
509521

510-
impl_stable_hash_for!(struct hir::Field {
511-
name,
512-
expr,
513-
span,
514-
is_shorthand
515-
});
522+
impl<'a> HashStable<StableHashingContext<'a>> for hir::Field {
523+
fn hash_stable<W: StableHasherResult>(&self,
524+
hcx: &mut StableHashingContext<'a>,
525+
hasher: &mut StableHasher<W>) {
526+
let hir::Field {
527+
id: _,
528+
name,
529+
ref expr,
530+
span,
531+
is_shorthand,
532+
} = *self;
533+
534+
name.hash_stable(hcx, hasher);
535+
expr.hash_stable(hcx, hasher);
536+
span.hash_stable(hcx, hasher);
537+
is_shorthand.hash_stable(hcx, hasher);
538+
}
539+
}
516540

517541
impl_stable_hash_for_spanned!(ast::Name);
518542

src/librustc/middle/dead.rs

+15-22
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
// from live codes are live, and everything else is dead.
1414

1515
use hir::map as hir_map;
16-
use hir::{self, Item_, PatKind};
16+
use hir::{self, PatKind};
1717
use hir::intravisit::{self, Visitor, NestedVisitorMap};
1818
use hir::itemlikevisit::ItemLikeVisitor;
1919

@@ -99,10 +99,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
9999
self.check_def_id(self.tables.type_dependent_defs()[id].def_id());
100100
}
101101

102-
fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
102+
fn handle_field_access(&mut self, lhs: &hir::Expr, node_id: ast::NodeId) {
103103
match self.tables.expr_ty_adjusted(lhs).sty {
104104
ty::TyAdt(def, _) => {
105-
self.insert_def_id(def.non_enum_variant().field_named(name).did);
105+
let index = self.tcx.field_index(node_id, self.tables);
106+
self.insert_def_id(def.non_enum_variant().fields[index].did);
106107
}
107108
ty::TyTuple(..) => {}
108109
_ => span_bug!(lhs.span, "named field access on non-ADT"),
@@ -119,7 +120,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
119120
if let PatKind::Wild = pat.node.pat.node {
120121
continue;
121122
}
122-
self.insert_def_id(variant.field_named(pat.node.name).did);
123+
let index = self.tcx.field_index(pat.node.id, self.tables);
124+
self.insert_def_id(variant.fields[index].did);
123125
}
124126
}
125127

@@ -182,18 +184,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
182184
self.inherited_pub_visibility = had_inherited_pub_visibility;
183185
}
184186

185-
fn mark_as_used_if_union(&mut self, did: DefId, fields: &hir::HirVec<hir::Field>) {
186-
if let Some(node_id) = self.tcx.hir.as_local_node_id(did) {
187-
if let Some(hir_map::NodeItem(item)) = self.tcx.hir.find(node_id) {
188-
if let Item_::ItemUnion(ref variant, _) = item.node {
189-
if variant.fields().len() > 1 {
190-
for field in variant.fields() {
191-
if fields.iter().find(|x| x.name.node == field.name).is_some() {
192-
self.live_symbols.insert(field.id);
193-
}
194-
}
195-
}
196-
}
187+
fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &hir::HirVec<hir::Field>) {
188+
if adt.is_union() && adt.non_enum_variant().fields.len() > 1 && adt.did.is_local() {
189+
for field in fields {
190+
let index = self.tcx.field_index(field.id, self.tables);
191+
self.insert_def_id(adt.non_enum_variant().fields[index].did);
197192
}
198193
}
199194
}
@@ -233,14 +228,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
233228
hir::ExprMethodCall(..) => {
234229
self.lookup_and_handle_method(expr.hir_id);
235230
}
236-
hir::ExprField(ref lhs, ref name) => {
237-
self.handle_field_access(&lhs, name.node);
231+
hir::ExprField(ref lhs, ..) => {
232+
self.handle_field_access(&lhs, expr.id);
238233
}
239234
hir::ExprStruct(_, ref fields, _) => {
240-
if let ty::TypeVariants::TyAdt(ref def, _) = self.tables.expr_ty(expr).sty {
241-
if def.is_union() {
242-
self.mark_as_used_if_union(def.did, fields);
243-
}
235+
if let ty::TypeVariants::TyAdt(ref adt, _) = self.tables.expr_ty(expr).sty {
236+
self.mark_as_used_if_union(adt, fields);
244237
}
245238
}
246239
_ => ()

src/librustc/middle/expr_use_visitor.rs

+6-10
Original file line numberDiff line numberDiff line change
@@ -659,11 +659,15 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
659659
match with_cmt.ty.sty {
660660
ty::TyAdt(adt, substs) if adt.is_struct() => {
661661
// Consume those fields of the with expression that are needed.
662-
for with_field in &adt.non_enum_variant().fields {
663-
if !contains_field_named(with_field, fields) {
662+
for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
663+
let is_mentioned = fields.iter().any(|f| {
664+
self.tcx().field_index(f.id, self.mc.tables) == f_index
665+
});
666+
if !is_mentioned {
664667
let cmt_field = self.mc.cat_field(
665668
&*with_expr,
666669
with_cmt.clone(),
670+
f_index,
667671
with_field.name,
668672
with_field.ty(self.tcx(), substs)
669673
);
@@ -687,14 +691,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
687691
// walk the with expression so that complex expressions
688692
// are properly handled.
689693
self.walk_expr(with_expr);
690-
691-
fn contains_field_named(field: &ty::FieldDef,
692-
fields: &[hir::Field])
693-
-> bool
694-
{
695-
fields.iter().any(
696-
|f| f.name.node == field.name)
697-
}
698694
}
699695

700696
// Invoke the appropriate delegate calls for anything that gets

src/librustc/middle/mem_categorization.rs

+28-11
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ use syntax::ast::{self, Name};
8484
use syntax_pos::Span;
8585

8686
use std::fmt;
87+
use std::hash::{Hash, Hasher};
8788
use rustc_data_structures::sync::Lrc;
8889
use std::rc::Rc;
8990
use util::nodemap::ItemLocalSet;
@@ -132,9 +133,22 @@ pub enum InteriorKind {
132133
InteriorElement(InteriorOffsetKind),
133134
}
134135

135-
// FIXME: Use actual index instead of `ast::Name` with questionable hygiene
136-
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
137-
pub struct FieldIndex(pub ast::Name);
136+
// Contains index of a field that is actually used for loan path comparisons and
137+
// string representation of the field that should be used only for diagnostics.
138+
#[derive(Clone, Copy, Eq)]
139+
pub struct FieldIndex(pub usize, pub Name);
140+
141+
impl PartialEq for FieldIndex {
142+
fn eq(&self, rhs: &Self) -> bool {
143+
self.0 == rhs.0
144+
}
145+
}
146+
147+
impl Hash for FieldIndex {
148+
fn hash<H: Hasher>(&self, h: &mut H) {
149+
self.0.hash(h)
150+
}
151+
}
138152

139153
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
140154
pub enum InteriorOffsetKind {
@@ -195,7 +209,7 @@ pub enum ImmutabilityBlame<'tcx> {
195209
}
196210

197211
impl<'tcx> cmt_<'tcx> {
198-
fn resolve_field(&self, field_name: Name) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
212+
fn resolve_field(&self, field_index: usize) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
199213
{
200214
let adt_def = match self.ty.sty {
201215
ty::TyAdt(def, _) => def,
@@ -212,7 +226,7 @@ impl<'tcx> cmt_<'tcx> {
212226
&adt_def.variants[0]
213227
}
214228
};
215-
Some((adt_def, variant_def.field_named(field_name)))
229+
Some((adt_def, &variant_def.fields[field_index]))
216230
}
217231

218232
pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
@@ -639,7 +653,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
639653
expr.id,
640654
expr,
641655
base_cmt);
642-
Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
656+
let f_index = self.tcx.field_index(expr.id, self.tables);
657+
Ok(self.cat_field(expr, base_cmt, f_index, f_name.node, expr_ty))
643658
}
644659

645660
hir::ExprIndex(ref base, _) => {
@@ -967,14 +982,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
967982
pub fn cat_field<N:ast_node>(&self,
968983
node: &N,
969984
base_cmt: cmt<'tcx>,
985+
f_index: usize,
970986
f_name: Name,
971987
f_ty: Ty<'tcx>)
972988
-> cmt<'tcx> {
973989
let ret = Rc::new(cmt_ {
974990
id: node.id(),
975991
span: node.span(),
976992
mutbl: base_cmt.mutbl.inherit(),
977-
cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_name))),
993+
cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_index, f_name))),
978994
ty: f_ty,
979995
note: NoteNone
980996
});
@@ -1262,7 +1278,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
12621278

12631279
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
12641280
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
1265-
let interior = InteriorField(FieldIndex(Name::intern(&i.to_string())));
1281+
let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
12661282
let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior);
12671283
self.cat_pattern_(subcmt, &subpat, op)?;
12681284
}
@@ -1285,7 +1301,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
12851301

12861302
for fp in field_pats {
12871303
let field_ty = self.pat_ty(&fp.node.pat)?; // see (*2)
1288-
let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.name, field_ty);
1304+
let f_index = self.tcx.field_index(fp.node.id, self.tables);
1305+
let cmt_field = self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty);
12891306
self.cat_pattern_(cmt_field, &fp.node.pat, op)?;
12901307
}
12911308
}
@@ -1302,7 +1319,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
13021319
};
13031320
for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
13041321
let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
1305-
let interior = InteriorField(FieldIndex(Name::intern(&i.to_string())));
1322+
let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string())));
13061323
let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior);
13071324
self.cat_pattern_(subcmt, &subpat, op)?;
13081325
}
@@ -1521,7 +1538,7 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
15211538
impl fmt::Debug for InteriorKind {
15221539
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15231540
match *self {
1524-
InteriorField(FieldIndex(name)) => write!(f, "{}", name),
1541+
InteriorField(FieldIndex(_, info)) => write!(f, "{}", info),
15251542
InteriorElement(..) => write!(f, "[]"),
15261543
}
15271544
}

src/librustc/ty/context.rs

+23
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,12 @@ pub struct TypeckTables<'tcx> {
346346
/// method calls, including those of overloaded operators.
347347
type_dependent_defs: ItemLocalMap<Def>,
348348

349+
/// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
350+
/// or patterns (`S { field }`). The index is often useful by itself, but to learn more
351+
/// about the field you also need definition of the variant to which the field
352+
/// belongs, but it may not exist if it's a tuple field (`tuple.0`).
353+
field_indices: ItemLocalMap<usize>,
354+
349355
/// Stores the canonicalized types provided by the user. See also `UserAssertTy` statement in
350356
/// MIR.
351357
user_provided_tys: ItemLocalMap<CanonicalTy<'tcx>>,
@@ -426,6 +432,7 @@ impl<'tcx> TypeckTables<'tcx> {
426432
TypeckTables {
427433
local_id_root,
428434
type_dependent_defs: ItemLocalMap(),
435+
field_indices: ItemLocalMap(),
429436
user_provided_tys: ItemLocalMap(),
430437
node_types: ItemLocalMap(),
431438
node_substs: ItemLocalMap(),
@@ -468,6 +475,20 @@ impl<'tcx> TypeckTables<'tcx> {
468475
}
469476
}
470477

478+
pub fn field_indices(&self) -> LocalTableInContext<usize> {
479+
LocalTableInContext {
480+
local_id_root: self.local_id_root,
481+
data: &self.field_indices
482+
}
483+
}
484+
485+
pub fn field_indices_mut(&mut self) -> LocalTableInContextMut<usize> {
486+
LocalTableInContextMut {
487+
local_id_root: self.local_id_root,
488+
data: &mut self.field_indices
489+
}
490+
}
491+
471492
pub fn user_provided_tys(&self) -> LocalTableInContext<CanonicalTy<'tcx>> {
472493
LocalTableInContext {
473494
local_id_root: self.local_id_root,
@@ -706,6 +727,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
706727
let ty::TypeckTables {
707728
local_id_root,
708729
ref type_dependent_defs,
730+
ref field_indices,
709731
ref user_provided_tys,
710732
ref node_types,
711733
ref node_substs,
@@ -726,6 +748,7 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for TypeckTables<'gcx> {
726748

727749
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
728750
type_dependent_defs.hash_stable(hcx, hasher);
751+
field_indices.hash_stable(hcx, hasher);
729752
user_provided_tys.hash_stable(hcx, hasher);
730753
node_types.hash_stable(hcx, hasher);
731754
node_substs.hash_stable(hcx, hasher);

0 commit comments

Comments
 (0)