Skip to content

Commit 3c6f410

Browse files
Ariel Ben-Yehudaarielb1
Ariel Ben-Yehuda
authored andcommitted
store the normalized types of field accesses
Fixes #31504
1 parent 350b50d commit 3c6f410

File tree

15 files changed

+150
-56
lines changed

15 files changed

+150
-56
lines changed

src/librustc/middle/ty/context.rs

+7
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ pub struct Tables<'tcx> {
131131
/// equivalents. This table is not used in trans (since regions
132132
/// are erased there) and hence is not serialized to metadata.
133133
pub liberated_fn_sigs: NodeMap<ty::FnSig<'tcx>>,
134+
135+
/// For each FRU expression, record the normalized types of the fields
136+
/// of the struct - this is needed because it is non-trivial to
137+
/// normalize while preserving regions. This table is used only in
138+
/// MIR construction and hence is not serialized to metadata.
139+
pub fru_field_types: NodeMap<Vec<Ty<'tcx>>>
134140
}
135141

136142
impl<'tcx> Tables<'tcx> {
@@ -144,6 +150,7 @@ impl<'tcx> Tables<'tcx> {
144150
closure_tys: DefIdMap(),
145151
closure_kinds: DefIdMap(),
146152
liberated_fn_sigs: NodeMap(),
153+
fru_field_types: NodeMap()
147154
}
148155
}
149156

src/librustc/mir/repr.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ pub struct Projection<'tcx, B, V> {
502502
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
503503
pub enum ProjectionElem<'tcx, V> {
504504
Deref,
505-
Field(Field),
505+
Field(Field, Ty<'tcx>),
506506
Index(V),
507507

508508
/// These indices are generated by slice patterns. Easiest to explain
@@ -553,8 +553,8 @@ impl Field {
553553
}
554554

555555
impl<'tcx> Lvalue<'tcx> {
556-
pub fn field(self, f: Field) -> Lvalue<'tcx> {
557-
self.elem(ProjectionElem::Field(f))
556+
pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> {
557+
self.elem(ProjectionElem::Field(f, ty))
558558
}
559559

560560
pub fn deref(self) -> Lvalue<'tcx> {
@@ -594,8 +594,8 @@ impl<'tcx> Debug for Lvalue<'tcx> {
594594
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name),
595595
ProjectionElem::Deref =>
596596
write!(fmt, "(*{:?})", data.base),
597-
ProjectionElem::Field(field) =>
598-
write!(fmt, "{:?}.{:?}", data.base, field.index()),
597+
ProjectionElem::Field(field, ty) =>
598+
write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty),
599599
ProjectionElem::Index(ref index) =>
600600
write!(fmt, "{:?}[{:?}]", data.base, index),
601601
ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>

src/librustc/mir/tcx.rs

+1-17
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,7 @@ impl<'tcx> LvalueTy<'tcx> {
7373
tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self))
7474
}
7575
},
76-
ProjectionElem::Field(field) => {
77-
let field_ty = match self {
78-
LvalueTy::Ty { ty } => match ty.sty {
79-
ty::TyStruct(adt_def, substs) =>
80-
adt_def.struct_variant().fields[field.index()].ty(tcx, substs),
81-
ty::TyTuple(ref tys) =>
82-
tys[field.index()],
83-
ty::TyClosure(_, ref closure_substs) =>
84-
closure_substs.upvar_tys[field.index()],
85-
_ =>
86-
tcx.sess.bug(&format!("cannot get field of type: `{:?}`", ty)),
87-
},
88-
LvalueTy::Downcast { adt_def, substs, variant_index } =>
89-
adt_def.variants[variant_index].fields[field.index()].ty(tcx, substs),
90-
};
91-
LvalueTy::Ty { ty: field_ty }
92-
}
76+
ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty }
9377
}
9478
}
9579
}

src/librustc_mir/build/expr/as_lvalue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
4141
}
4242
ExprKind::Field { lhs, name } => {
4343
let lvalue = unpack!(block = this.as_lvalue(block, lhs));
44-
let lvalue = lvalue.field(name);
44+
let lvalue = lvalue.field(name, expr.ty);
4545
block.and(lvalue)
4646
}
4747
ExprKind::Deref { arg } => {

src/librustc_mir/build/expr/as_rvalue.rs

+14-17
Original file line numberDiff line numberDiff line change
@@ -139,33 +139,30 @@ impl<'a,'tcx> Builder<'a,'tcx> {
139139
.collect();
140140
block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars))
141141
}
142-
ExprKind::Adt { adt_def, variant_index, substs, fields, base } => { // see (*) above
142+
ExprKind::Adt {
143+
adt_def, variant_index, substs, fields, base
144+
} => { // see (*) above
143145
// first process the set of fields that were provided
144146
// (evaluating them in order given by user)
145147
let fields_map: FnvHashMap<_, _> =
146148
fields.into_iter()
147149
.map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr))))
148150
.collect();
149151

150-
// if base expression is given, evaluate it now
151-
let base = base.map(|base| unpack!(block = this.as_lvalue(block, base)));
152-
153-
// get list of all fields that we will need
154152
let field_names = this.hir.all_fields(adt_def, variant_index);
155153

156-
// for the actual values we use, take either the
157-
// expr the user specified or, if they didn't
158-
// specify something for this field name, create a
159-
// path relative to the base (which must have been
160-
// supplied, or the IR is internally
161-
// inconsistent).
162-
let fields: Vec<_> =
154+
let fields = if let Some(FruInfo { base, field_types }) = base {
155+
let base = unpack!(block = this.as_lvalue(block, base));
163156
field_names.into_iter()
164-
.map(|n| match fields_map.get(&n) {
165-
Some(v) => v.clone(),
166-
None => Operand::Consume(base.clone().unwrap().field(n)),
167-
})
168-
.collect();
157+
.zip(field_types.into_iter())
158+
.map(|(n, ty)| match fields_map.get(&n) {
159+
Some(v) => v.clone(),
160+
None => Operand::Consume(base.clone().field(n, ty))
161+
})
162+
.collect()
163+
} else {
164+
field_names.iter().map(|n| fields_map[n].clone()).collect()
165+
};
169166

170167
block.and(Rvalue::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs),
171168
fields))

src/librustc_mir/build/matches/test.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
404404
subpatterns.iter()
405405
.map(|subpattern| {
406406
// e.g., `(x as Variant).0`
407-
let lvalue = downcast_lvalue.clone().field(subpattern.field);
407+
let lvalue = downcast_lvalue.clone().field(subpattern.field,
408+
subpattern.field_ty());
408409
// e.g., `(x as Variant).0 @ P1`
409410
MatchPair::new(lvalue, &subpattern.pattern)
410411
});

src/librustc_mir/build/matches/util.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
2121
-> Vec<MatchPair<'pat, 'tcx>> {
2222
subpatterns.iter()
2323
.map(|fieldpat| {
24-
let lvalue = lvalue.clone().field(fieldpat.field);
24+
let lvalue = lvalue.clone().field(fieldpat.field,
25+
fieldpat.field_ty());
2526
MatchPair::new(lvalue, &fieldpat.pattern)
2627
})
2728
.collect()

src/librustc_mir/hair/cx/expr.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -248,21 +248,31 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
248248
variant_index: 0,
249249
substs: substs,
250250
fields: field_refs,
251-
base: base.to_ref(),
251+
base: base.as_ref().map(|base| {
252+
FruInfo {
253+
base: base.to_ref(),
254+
field_types: cx.tcx.tables
255+
.borrow()
256+
.fru_field_types[&self.id]
257+
.clone()
258+
}
259+
})
252260
}
253261
}
254262
ty::TyEnum(adt, substs) => {
255263
match cx.tcx.def_map.borrow()[&self.id].full_def() {
256264
Def::Variant(enum_id, variant_id) => {
257265
debug_assert!(adt.did == enum_id);
266+
assert!(base.is_none());
267+
258268
let index = adt.variant_index_with_id(variant_id);
259269
let field_refs = field_refs(&adt.variants[index], fields);
260270
ExprKind::Adt {
261271
adt_def: adt,
262272
variant_index: index,
263273
substs: substs,
264274
fields: field_refs,
265-
base: base.to_ref(),
275+
base: None
266276
}
267277
}
268278
ref def => {
@@ -810,11 +820,16 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
810820
};
811821
match upvar_capture {
812822
ty::UpvarCapture::ByValue => field_kind,
813-
ty::UpvarCapture::ByRef(_) => {
823+
ty::UpvarCapture::ByRef(borrow) => {
814824
ExprKind::Deref {
815825
arg: Expr {
816826
temp_lifetime: temp_lifetime,
817-
ty: var_ty,
827+
ty: cx.tcx.mk_ref(
828+
cx.tcx.mk_region(borrow.region),
829+
ty::TypeAndMut {
830+
ty: var_ty,
831+
mutbl: borrow.kind.to_mutbl_lossy()
832+
}),
818833
span: expr.span,
819834
kind: field_kind,
820835
}.to_ref()

src/librustc_mir/hair/cx/pattern.rs

+17
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,20 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
314314
}
315315
}
316316
}
317+
318+
impl<'tcx> FieldPattern<'tcx> {
319+
pub fn field_ty(&self) -> Ty<'tcx> {
320+
debug!("field_ty({:?},ty={:?})", self, self.pattern.ty);
321+
let r = match *self.pattern.kind {
322+
PatternKind::Binding { mode: BindingMode::ByRef(..), ..} => {
323+
match self.pattern.ty.sty {
324+
ty::TyRef(_, mt) => mt.ty,
325+
_ => unreachable!()
326+
}
327+
}
328+
_ => self.pattern.ty
329+
};
330+
debug!("field_ty -> {:?}", r);
331+
r
332+
}
333+
}

src/librustc_mir/hair/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ pub enum ExprKind<'tcx> {
229229
variant_index: usize,
230230
substs: &'tcx Substs<'tcx>,
231231
fields: Vec<FieldExprRef<'tcx>>,
232-
base: Option<ExprRef<'tcx>>,
232+
base: Option<FruInfo<'tcx>>
233233
},
234234
Closure {
235235
closure_id: DefId,
@@ -256,6 +256,12 @@ pub struct FieldExprRef<'tcx> {
256256
pub expr: ExprRef<'tcx>,
257257
}
258258

259+
#[derive(Clone, Debug)]
260+
pub struct FruInfo<'tcx> {
261+
pub base: ExprRef<'tcx>,
262+
pub field_types: Vec<Ty<'tcx>>
263+
}
264+
259265
#[derive(Clone, Debug)]
260266
pub struct Arm<'tcx> {
261267
pub patterns: Vec<Pattern<'tcx>>,

src/librustc_mir/transform/type_check.rs

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'tcx> {
4747

4848
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: visit::LvalueContext) {
4949
self.super_lvalue(lvalue, context);
50+
debug!("visiting lvalue {:?}", lvalue);
5051
let lv_ty = self.mir.lvalue_ty(self.tcx(), lvalue).to_ty(self.tcx());
5152
self.sanitize_type(lvalue, lv_ty);
5253
}

src/librustc_trans/trans/mir/lvalue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
126126
}
127127
})
128128
}
129-
mir::ProjectionElem::Field(ref field) => {
129+
mir::ProjectionElem::Field(ref field, _) => {
130130
let base_ty = tr_base.ty.to_ty(tcx);
131131
let base_repr = adt::represent_type(ccx, base_ty);
132132
let discr = match tr_base.ty {

src/librustc_typeck/check/mod.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -3179,8 +3179,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
31793179
check_struct_fields_on_error(fcx, expr.id, fields, base_expr);
31803180
return;
31813181
}
3182-
let (adt, variant) = match fcx.def_struct_variant(def, path.span) {
3183-
Some((adt, variant)) => (adt, variant),
3182+
let variant = match fcx.def_struct_variant(def, path.span) {
3183+
Some((_, variant)) => variant,
31843184
None => {
31853185
span_err!(fcx.tcx().sess, path.span, E0071,
31863186
"`{}` does not name a structure",
@@ -3195,12 +3195,23 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
31953195

31963196
check_expr_struct_fields(fcx, expr_ty, expr.span, variant, fields,
31973197
base_expr.is_none());
3198-
31993198
if let &Some(ref base_expr) = base_expr {
32003199
check_expr_has_type(fcx, base_expr, expr_ty);
3201-
if adt.adt_kind() == ty::AdtKind::Enum {
3202-
span_err!(tcx.sess, base_expr.span, E0436,
3203-
"functional record update syntax requires a struct");
3200+
match expr_ty.sty {
3201+
ty::TyStruct(adt, substs) => {
3202+
fcx.inh.tables.borrow_mut().fru_field_types.insert(
3203+
expr.id,
3204+
adt.struct_variant().fields.iter().map(|f| {
3205+
fcx.normalize_associated_types_in(
3206+
expr.span, &f.ty(tcx, substs)
3207+
)
3208+
}).collect()
3209+
);
3210+
}
3211+
_ => {
3212+
span_err!(tcx.sess, base_expr.span, E0436,
3213+
"functional record update syntax requires a struct");
3214+
}
32043215
}
32053216
}
32063217
}

src/librustc_typeck/check/writeback.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) {
4343
wbcx.visit_upvar_borrow_map();
4444
wbcx.visit_closures();
4545
wbcx.visit_liberated_fn_sigs();
46+
wbcx.visit_fru_field_types();
4647
}
4748

4849
pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
@@ -64,6 +65,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
6465
wbcx.visit_upvar_borrow_map();
6566
wbcx.visit_closures();
6667
wbcx.visit_liberated_fn_sigs();
68+
wbcx.visit_fru_field_types();
6769
}
6870

6971
///////////////////////////////////////////////////////////////////////////
@@ -371,6 +373,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
371373
}
372374
}
373375

376+
fn visit_fru_field_types(&self) {
377+
for (&node_id, ftys) in self.fcx.inh.tables.borrow().fru_field_types.iter() {
378+
let ftys = self.resolve(ftys, ResolvingFieldTypes(node_id));
379+
self.tcx().tables.borrow_mut().fru_field_types.insert(node_id, ftys);
380+
}
381+
}
382+
374383
fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
375384
t.fold_with(&mut Resolver::new(self.fcx, reason))
376385
}
@@ -387,6 +396,7 @@ enum ResolveReason {
387396
ResolvingUpvar(ty::UpvarId),
388397
ResolvingClosure(DefId),
389398
ResolvingFnSig(ast::NodeId),
399+
ResolvingFieldTypes(ast::NodeId)
390400
}
391401

392402
impl ResolveReason {
@@ -401,6 +411,9 @@ impl ResolveReason {
401411
ResolvingFnSig(id) => {
402412
tcx.map.span(id)
403413
}
414+
ResolvingFieldTypes(id) => {
415+
tcx.map.span(id)
416+
}
404417
ResolvingClosure(did) => {
405418
if let Some(node_id) = tcx.map.as_local_node_id(did) {
406419
tcx.expr_span(node_id)
@@ -478,14 +491,14 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
478491
"cannot determine a type for this closure")
479492
}
480493

481-
ResolvingFnSig(id) => {
494+
ResolvingFnSig(id) | ResolvingFieldTypes(id) => {
482495
// any failures here should also fail when
483496
// resolving the patterns, closure types, or
484497
// something else.
485498
let span = self.reason.span(self.tcx);
486499
self.tcx.sess.delay_span_bug(
487500
span,
488-
&format!("cannot resolve some aspect of fn sig for {:?}", id));
501+
&format!("cannot resolve some aspect of data for {:?}", id));
489502
}
490503
}
491504
}

0 commit comments

Comments
 (0)