Skip to content

Commit 2a339ce

Browse files
Structurally normalize types as needed in projection_ty_core
1 parent 38081f2 commit 2a339ce

File tree

4 files changed

+81
-45
lines changed

4 files changed

+81
-45
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -474,17 +474,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
474474
let projected_ty = curr_projected_ty.projection_ty_core(
475475
tcx,
476476
proj,
477-
|this, field, ()| {
478-
let ty = this.field_ty(tcx, field);
479-
self.structurally_resolve(ty, locations)
480-
},
481-
|_, _| unreachable!(),
477+
|ty| self.structurally_resolve(ty, locations),
478+
|ty, variant_index, field, ()| PlaceTy::field_ty(tcx, ty, variant_index, field),
479+
|_| unreachable!(),
482480
);
483481
curr_projected_ty = projected_ty;
484482
}
485483
trace!(?curr_projected_ty);
486484

487-
let ty = curr_projected_ty.ty;
485+
let ty = self.normalize(curr_projected_ty.ty, locations);
488486
self.relate_types(ty, v.xform(ty::Contravariant), a, locations, category)?;
489487

490488
Ok(())
@@ -1852,7 +1850,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
18521850
| ProjectionElem::Downcast(..) => {}
18531851
ProjectionElem::Field(field, fty) => {
18541852
let fty = self.normalize(fty, location);
1855-
let ty = base_ty.field_ty(tcx, field);
1853+
let ty = PlaceTy::field_ty(tcx, base_ty.ty, base_ty.variant_index, field);
18561854
let ty = self.normalize(ty, location);
18571855
debug!(?fty, ?ty);
18581856

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -88,26 +88,31 @@ impl<'tcx> PlaceTy<'tcx> {
8888
///
8989
/// Note that the resulting type has not been normalized.
9090
#[instrument(level = "debug", skip(tcx), ret)]
91-
pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: FieldIdx) -> Ty<'tcx> {
92-
if let Some(variant_index) = self.variant_index {
93-
match *self.ty.kind() {
91+
pub fn field_ty(
92+
tcx: TyCtxt<'tcx>,
93+
self_ty: Ty<'tcx>,
94+
variant_idx: Option<VariantIdx>,
95+
f: FieldIdx,
96+
) -> Ty<'tcx> {
97+
if let Some(variant_index) = variant_idx {
98+
match *self_ty.kind() {
9499
ty::Adt(adt_def, args) if adt_def.is_enum() => {
95100
adt_def.variant(variant_index).fields[f].ty(tcx, args)
96101
}
97102
ty::Coroutine(def_id, args) => {
98103
let mut variants = args.as_coroutine().state_tys(def_id, tcx);
99104
let Some(mut variant) = variants.nth(variant_index.into()) else {
100-
bug!("variant {variant_index:?} of coroutine out of range: {self:?}");
105+
bug!("variant {variant_index:?} of coroutine out of range: {self_ty:?}");
101106
};
102107

103-
variant
104-
.nth(f.index())
105-
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}"))
108+
variant.nth(f.index()).unwrap_or_else(|| {
109+
bug!("field {f:?} out of range of variant: {self_ty:?} {variant_idx:?}")
110+
})
106111
}
107-
_ => bug!("can't downcast non-adt non-coroutine type: {self:?}"),
112+
_ => bug!("can't downcast non-adt non-coroutine type: {self_ty:?}"),
108113
}
109114
} else {
110-
match self.ty.kind() {
115+
match self_ty.kind() {
111116
ty::Adt(adt_def, args) if !adt_def.is_enum() => {
112117
adt_def.non_enum_variant().fields[f].ty(tcx, args)
113118
}
@@ -116,26 +121,25 @@ impl<'tcx> PlaceTy<'tcx> {
116121
.upvar_tys()
117122
.get(f.index())
118123
.copied()
119-
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
124+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")),
120125
ty::CoroutineClosure(_, args) => args
121126
.as_coroutine_closure()
122127
.upvar_tys()
123128
.get(f.index())
124129
.copied()
125-
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
130+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")),
126131
// Only prefix fields (upvars and current state) are
127132
// accessible without a variant index.
128-
ty::Coroutine(_, args) => args
129-
.as_coroutine()
130-
.prefix_tys()
131-
.get(f.index())
132-
.copied()
133-
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
133+
ty::Coroutine(_, args) => {
134+
args.as_coroutine().prefix_tys().get(f.index()).copied().unwrap_or_else(|| {
135+
bug!("field {f:?} out of range of prefixes for {self_ty}")
136+
})
137+
}
134138
ty::Tuple(tys) => tys
135139
.get(f.index())
136140
.copied()
137-
.unwrap_or_else(|| bug!("field {f:?} out of range: {self:?}")),
138-
_ => bug!("can't project out of {self:?}"),
141+
.unwrap_or_else(|| bug!("field {f:?} out of range: {self_ty:?}")),
142+
_ => bug!("can't project out of {self_ty:?}"),
139143
}
140144
}
141145
}
@@ -148,11 +152,11 @@ impl<'tcx> PlaceTy<'tcx> {
148152
elems.iter().fold(self, |place_ty, &elem| place_ty.projection_ty(tcx, elem))
149153
}
150154

151-
/// Convenience wrapper around `projection_ty_core` for
152-
/// `PlaceElem`, where we can just use the `Ty` that is already
153-
/// stored inline on field projection elems.
155+
/// Convenience wrapper around `projection_ty_core` for `PlaceElem`,
156+
/// where we can just use the `Ty` that is already stored inline on
157+
/// field projection elems.
154158
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
155-
self.projection_ty_core(tcx, &elem, |_, _, ty| ty, |_, ty| ty)
159+
self.projection_ty_core(tcx, &elem, |ty| ty, |_, _, _, ty| ty, |ty| ty)
156160
}
157161

158162
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -164,8 +168,9 @@ impl<'tcx> PlaceTy<'tcx> {
164168
self,
165169
tcx: TyCtxt<'tcx>,
166170
elem: &ProjectionElem<V, T>,
167-
mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>,
168-
mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>,
171+
mut structurally_normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
172+
mut handle_field: impl FnMut(Ty<'tcx>, Option<VariantIdx>, FieldIdx, T) -> Ty<'tcx>,
173+
mut handle_opaque_cast_and_subtype: impl FnMut(T) -> Ty<'tcx>,
169174
) -> PlaceTy<'tcx>
170175
where
171176
V: ::std::fmt::Debug,
@@ -176,16 +181,16 @@ impl<'tcx> PlaceTy<'tcx> {
176181
}
177182
let answer = match *elem {
178183
ProjectionElem::Deref => {
179-
let ty = self.ty.builtin_deref(true).unwrap_or_else(|| {
184+
let ty = structurally_normalize(self.ty).builtin_deref(true).unwrap_or_else(|| {
180185
bug!("deref projection of non-dereferenceable ty {:?}", self)
181186
});
182187
PlaceTy::from_ty(ty)
183188
}
184189
ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
185-
PlaceTy::from_ty(self.ty.builtin_index().unwrap())
190+
PlaceTy::from_ty(structurally_normalize(self.ty).builtin_index().unwrap())
186191
}
187192
ProjectionElem::Subslice { from, to, from_end } => {
188-
PlaceTy::from_ty(match self.ty.kind() {
193+
PlaceTy::from_ty(match structurally_normalize(self.ty).kind() {
189194
ty::Slice(..) => self.ty,
190195
ty::Array(inner, _) if !from_end => Ty::new_array(tcx, *inner, to - from),
191196
ty::Array(inner, size) if from_end => {
@@ -201,17 +206,18 @@ impl<'tcx> PlaceTy<'tcx> {
201206
ProjectionElem::Downcast(_name, index) => {
202207
PlaceTy { ty: self.ty, variant_index: Some(index) }
203208
}
204-
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
205-
ProjectionElem::OpaqueCast(ty) => {
206-
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
207-
}
208-
ProjectionElem::Subtype(ty) => {
209-
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
210-
}
209+
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(
210+
structurally_normalize(self.ty),
211+
self.variant_index,
212+
f,
213+
fty,
214+
)),
215+
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
216+
ProjectionElem::Subtype(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
211217

212218
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
213219
ProjectionElem::UnwrapUnsafeBinder(ty) => {
214-
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
220+
PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty))
215221
}
216222
};
217223
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);

compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> {
323323
fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
324324
let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
325325
@call(mir_field, args) => {
326-
let (parent, ty) = self.parse_place_inner(args[0])?;
326+
let (parent, place_ty) = self.parse_place_inner(args[0])?;
327327
let field = FieldIdx::from_u32(self.parse_integer_literal(args[1])? as u32);
328-
let field_ty = ty.field_ty(self.tcx, field);
328+
let field_ty = PlaceTy::field_ty(self.tcx, place_ty.ty, place_ty.variant_index, field);
329329
let proj = PlaceElem::Field(field, field_ty);
330330
let place = parent.project_deeper(&[proj], self.tcx);
331331
return Ok((place, PlaceTy::from_ty(field_ty)));
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ check-pass
2+
//@ compile-flags: -Znext-solver
3+
4+
// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/221>.
5+
// Ensure that we normalize after applying projection elems in MIR typeck.
6+
7+
use std::marker::PhantomData;
8+
9+
#[derive(Copy, Clone)]
10+
struct Span;
11+
12+
trait AstKind {
13+
type Inner;
14+
}
15+
16+
struct WithSpan;
17+
impl AstKind for WithSpan {
18+
type Inner
19+
= (i32,);
20+
}
21+
22+
struct Expr<'a> { f: &'a <WithSpan as AstKind>::Inner }
23+
24+
impl Expr<'_> {
25+
fn span(self) {
26+
match self {
27+
Self { f: (n,) } => {},
28+
}
29+
}
30+
}
31+
32+
fn main() {}

0 commit comments

Comments
 (0)