Skip to content

Commit 6f8fb91

Browse files
authored
Rollup merge of rust-lang#98582 - oli-obk:unconstrained_opaque_type, r=estebank
Allow destructuring opaque types in their defining scopes fixes rust-lang#96572 Before this PR, the following code snippet failed with an incomprehensible error, and similar code just ICEd in mir borrowck. ```rust type T = impl Copy; let foo: T = (1u32, 2u32); let (a, b) = foo; ``` The problem was that the last line created MIR projections of the form `foo.0` and `foo.1`, but `foo`'s type is `T`, which doesn't have fields (only its hidden type does). But the pattern supplies enough type information (a tuple of two different inference types) to bind a hidden type.
2 parents 7210e46 + 57e9f7a commit 6f8fb91

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+396
-205
lines changed

Diff for: compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2093,7 +2093,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
20932093
}
20942094
StorageDeadOrDrop::Destructor(_) => kind,
20952095
},
2096-
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
2096+
ProjectionElem::OpaqueCast { .. }
2097+
| ProjectionElem::Field(..)
2098+
| ProjectionElem::Downcast(..) => {
20972099
match place_ty.ty.kind() {
20982100
ty::Adt(def, _) if def.has_dtor(tcx) => {
20992101
// Report the outermost adt with a destructor

Diff for: compiler/rustc_borrowck/src/diagnostics/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
226226
}
227227
ProjectionElem::Downcast(..) if including_downcast.0 => return None,
228228
ProjectionElem::Downcast(..) => (),
229+
ProjectionElem::OpaqueCast(..) => (),
229230
ProjectionElem::Field(field, _ty) => {
230231
// FIXME(project-rfc_2229#36): print capture precisely here.
231232
if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@@ -286,6 +287,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
286287
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
287288
}
288289
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
290+
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty),
289291
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
290292
},
291293
};

Diff for: compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
169169
..,
170170
ProjectionElem::Index(_)
171171
| ProjectionElem::ConstantIndex { .. }
172+
| ProjectionElem::OpaqueCast { .. }
172173
| ProjectionElem::Subslice { .. }
173174
| ProjectionElem::Downcast(..),
174175
],

Diff for: compiler/rustc_borrowck/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1788,6 +1788,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
17881788
for (place_base, elem) in place.iter_projections().rev() {
17891789
match elem {
17901790
ProjectionElem::Index(_/*operand*/) |
1791+
ProjectionElem::OpaqueCast(_) |
17911792
ProjectionElem::ConstantIndex { .. } |
17921793
// assigning to P[i] requires P to be valid.
17931794
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
@@ -2179,6 +2180,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
21792180
| ProjectionElem::Index(..)
21802181
| ProjectionElem::ConstantIndex { .. }
21812182
| ProjectionElem::Subslice { .. }
2183+
| ProjectionElem::OpaqueCast { .. }
21822184
| ProjectionElem::Downcast(..) => {
21832185
let upvar_field_projection = self.is_upvar_field_projection(place);
21842186
if let Some(field) = upvar_field_projection {

Diff for: compiler/rustc_borrowck/src/places_conflict.rs

+13
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ fn place_components_conflict<'tcx>(
255255
| (ProjectionElem::Index { .. }, _, _)
256256
| (ProjectionElem::ConstantIndex { .. }, _, _)
257257
| (ProjectionElem::Subslice { .. }, _, _)
258+
| (ProjectionElem::OpaqueCast { .. }, _, _)
258259
| (ProjectionElem::Downcast { .. }, _, _) => {
259260
// Recursive case. This can still be disjoint on a
260261
// further iteration if this a shallow access and
@@ -322,6 +323,17 @@ fn place_projection_conflict<'tcx>(
322323
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
323324
Overlap::EqualOrDisjoint
324325
}
326+
(ProjectionElem::OpaqueCast(v1), ProjectionElem::OpaqueCast(v2)) => {
327+
if v1 == v2 {
328+
// same type - recur.
329+
debug!("place_element_conflict: DISJOINT-OR-EQ-OPAQUE");
330+
Overlap::EqualOrDisjoint
331+
} else {
332+
// Different types. Disjoint!
333+
debug!("place_element_conflict: DISJOINT-OPAQUE");
334+
Overlap::Disjoint
335+
}
336+
}
325337
(ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {
326338
if f1 == f2 {
327339
// same field (e.g., `a.y` vs. `a.y`) - recur.
@@ -525,6 +537,7 @@ fn place_projection_conflict<'tcx>(
525537
| ProjectionElem::Field(..)
526538
| ProjectionElem::Index(..)
527539
| ProjectionElem::ConstantIndex { .. }
540+
| ProjectionElem::OpaqueCast { .. }
528541
| ProjectionElem::Subslice { .. }
529542
| ProjectionElem::Downcast(..),
530543
_,

Diff for: compiler/rustc_borrowck/src/prefixes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> {
8181
}
8282
ProjectionElem::Downcast(..)
8383
| ProjectionElem::Subslice { .. }
84+
| ProjectionElem::OpaqueCast { .. }
8485
| ProjectionElem::ConstantIndex { .. }
8586
| ProjectionElem::Index(_) => {
8687
cursor = cursor_base;

Diff for: compiler/rustc_borrowck/src/type_check/mod.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,19 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
790790
}
791791
PlaceTy::from_ty(fty)
792792
}
793+
ProjectionElem::OpaqueCast(ty) => {
794+
let ty = self.sanitize_type(place, ty);
795+
let ty = self.cx.normalize(ty, location);
796+
self.cx
797+
.eq_types(
798+
base.ty,
799+
ty,
800+
location.to_locations(),
801+
ConstraintCategory::TypeAnnotation,
802+
)
803+
.unwrap();
804+
PlaceTy::from_ty(ty)
805+
}
793806
}
794807
}
795808

@@ -1195,10 +1208,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
11951208
tcx,
11961209
self.param_env,
11971210
proj,
1198-
|this, field, ()| {
1211+
|this, field, _| {
11991212
let ty = this.field_ty(tcx, field);
12001213
self.normalize(ty, locations)
12011214
},
1215+
|_, _| unreachable!(),
12021216
);
12031217
curr_projected_ty = projected_ty;
12041218
}
@@ -2493,6 +2507,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
24932507
}
24942508
ProjectionElem::Field(..)
24952509
| ProjectionElem::Downcast(..)
2510+
| ProjectionElem::OpaqueCast(..)
24962511
| ProjectionElem::Index(..)
24972512
| ProjectionElem::ConstantIndex { .. }
24982513
| ProjectionElem::Subslice { .. } => {

Diff for: compiler/rustc_codegen_cranelift/src/base.rs

+1
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ pub(crate) fn codegen_place<'tcx>(
825825
cplace = cplace.place_deref(fx);
826826
}
827827
}
828+
PlaceElem::OpaqueCast(ty) => cplace = cplace.place_opaque_cast(fx, ty),
828829
PlaceElem::Field(field, _ty) => {
829830
cplace = cplace.place_field(fx, field);
830831
}

Diff for: compiler/rustc_codegen_cranelift/src/value_and_place.rs

+8
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,14 @@ impl<'tcx> CPlace<'tcx> {
615615
}
616616
}
617617

618+
pub(crate) fn place_opaque_cast(
619+
self,
620+
fx: &mut FunctionCx<'_, '_, 'tcx>,
621+
ty: Ty<'tcx>,
622+
) -> CPlace<'tcx> {
623+
CPlace { inner: self.inner, layout: fx.layout_of(ty) }
624+
}
625+
618626
pub(crate) fn place_field(
619627
self,
620628
fx: &mut FunctionCx<'_, '_, 'tcx>,

Diff for: compiler/rustc_codegen_ssa/src/mir/place.rs

+16
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,21 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
411411
downcast
412412
}
413413

414+
pub fn project_type<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
415+
&self,
416+
bx: &mut Bx,
417+
ty: Ty<'tcx>,
418+
) -> Self {
419+
let mut downcast = *self;
420+
downcast.layout = bx.cx().layout_of(ty);
421+
422+
// Cast to the appropriate type.
423+
let variant_ty = bx.cx().backend_type(downcast.layout);
424+
downcast.llval = bx.pointercast(downcast.llval, bx.cx().type_ptr_to(variant_ty));
425+
426+
downcast
427+
}
428+
414429
pub fn storage_live<Bx: BuilderMethods<'a, 'tcx, Value = V>>(&self, bx: &mut Bx) {
415430
bx.lifetime_start(self.llval, self.layout.size);
416431
}
@@ -459,6 +474,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
459474
mir::ProjectionElem::Field(ref field, _) => {
460475
cg_base.project_field(bx, field.index())
461476
}
477+
mir::ProjectionElem::OpaqueCast(ty) => cg_base.project_type(bx, ty),
462478
mir::ProjectionElem::Index(index) => {
463479
let index = &mir::Operand::Copy(mir::Place::from(index));
464480
let index = self.codegen_operand(bx, index);

Diff for: compiler/rustc_const_eval/src/interpret/projection.rs

+10
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,11 @@ where
351351
) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
352352
use rustc_middle::mir::ProjectionElem::*;
353353
Ok(match proj_elem {
354+
OpaqueCast(ty) => {
355+
let mut place = *base;
356+
place.layout = self.layout_of(ty)?;
357+
place
358+
}
354359
Field(field, _) => self.place_field(base, field.index())?,
355360
Downcast(_, variant) => self.place_downcast(base, variant)?,
356361
Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
@@ -375,6 +380,11 @@ where
375380
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
376381
use rustc_middle::mir::ProjectionElem::*;
377382
Ok(match proj_elem {
383+
OpaqueCast(ty) => {
384+
let mut op = *base;
385+
op.layout = self.layout_of(ty)?;
386+
op
387+
}
378388
Field(field, _) => self.operand_field(base, field.index())?,
379389
Downcast(_, variant) => self.operand_downcast(base, variant)?,
380390
Deref => self.deref_operand(base)?.into(),

Diff for: compiler/rustc_const_eval/src/transform/check_consts/check.rs

+1
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
652652

653653
ProjectionElem::ConstantIndex { .. }
654654
| ProjectionElem::Downcast(..)
655+
| ProjectionElem::OpaqueCast(..)
655656
| ProjectionElem::Subslice { .. }
656657
| ProjectionElem::Field(..)
657658
| ProjectionElem::Index(_) => {}

Diff for: compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ where
316316

317317
ProjectionElem::Deref
318318
| ProjectionElem::Field(_, _)
319+
| ProjectionElem::OpaqueCast(_)
319320
| ProjectionElem::ConstantIndex { .. }
320321
| ProjectionElem::Subslice { .. }
321322
| ProjectionElem::Downcast(_, _)

Diff for: compiler/rustc_const_eval/src/transform/promote_consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ impl<'tcx> Validator<'_, 'tcx> {
361361
return Err(Unpromotable);
362362
}
363363
}
364-
ProjectionElem::Downcast(..) => {
364+
ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
365365
return Err(Unpromotable);
366366
}
367367

Diff for: compiler/rustc_middle/src/mir/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,7 @@ impl<V, T> ProjectionElem<V, T> {
13971397

13981398
Self::Field(_, _)
13991399
| Self::Index(_)
1400+
| Self::OpaqueCast(_)
14001401
| Self::ConstantIndex { .. }
14011402
| Self::Subslice { .. }
14021403
| Self::Downcast(_, _) => false,
@@ -1574,7 +1575,9 @@ impl Debug for Place<'_> {
15741575
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
15751576
for elem in self.projection.iter().rev() {
15761577
match elem {
1577-
ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => {
1578+
ProjectionElem::OpaqueCast(_)
1579+
| ProjectionElem::Downcast(_, _)
1580+
| ProjectionElem::Field(_, _) => {
15781581
write!(fmt, "(").unwrap();
15791582
}
15801583
ProjectionElem::Deref => {
@@ -1590,6 +1593,9 @@ impl Debug for Place<'_> {
15901593

15911594
for elem in self.projection.iter() {
15921595
match elem {
1596+
ProjectionElem::OpaqueCast(ty) => {
1597+
write!(fmt, " as {})", ty)?;
1598+
}
15931599
ProjectionElem::Downcast(Some(name), _index) => {
15941600
write!(fmt, " as {})", name)?;
15951601
}

Diff for: compiler/rustc_middle/src/mir/syntax.rs

+7
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,9 @@ pub type AssertMessage<'tcx> = AssertKind<Operand<'tcx>>;
754754
/// generator has more than one variant, the parent place's variant index must be set, indicating
755755
/// which variant is being used. If it has just one variant, the variant index may or may not be
756756
/// included - the single possible variant is inferred if it is not included.
757+
/// - [`OpaqueCast`](ProjectionElem::OpaqueCast): This projection changes the place's type to the
758+
/// given one, and makes no other changes. A `OpaqueCast` projection on any type other than an
759+
/// opaque type from the current crate is not well-formed.
757760
/// - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
758761
/// place as described in the documentation for the `ProjectionElem`. The resulting address is
759762
/// the parent's address plus that offset, and the type is `T`. This is only legal if the parent
@@ -856,6 +859,10 @@ pub enum ProjectionElem<V, T> {
856859
///
857860
/// The included Symbol is the name of the variant, used for printing MIR.
858861
Downcast(Option<Symbol>, VariantIdx),
862+
863+
/// Like an explicit cast from an opaque type to a concrete type, but without
864+
/// requiring an intermediate variable.
865+
OpaqueCast(T),
859866
}
860867

861868
/// Alias for projections as they appear in places, where the base is a place

Diff for: compiler/rustc_middle/src/mir/tcx.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl<'tcx> PlaceTy<'tcx> {
5757
/// `PlaceElem`, where we can just use the `Ty` that is already
5858
/// stored inline on field projection elems.
5959
pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
60-
self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
60+
self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty, |_, ty| ty)
6161
}
6262

6363
/// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -71,6 +71,7 @@ impl<'tcx> PlaceTy<'tcx> {
7171
param_env: ty::ParamEnv<'tcx>,
7272
elem: &ProjectionElem<V, T>,
7373
mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>,
74+
mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>,
7475
) -> PlaceTy<'tcx>
7576
where
7677
V: ::std::fmt::Debug,
@@ -109,6 +110,7 @@ impl<'tcx> PlaceTy<'tcx> {
109110
PlaceTy { ty: self.ty, variant_index: Some(index) }
110111
}
111112
ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)),
113+
ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)),
112114
};
113115
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
114116
answer

Diff for: compiler/rustc_middle/src/mir/type_foldable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
182182
Ok(match self {
183183
Deref => Deref,
184184
Field(f, ty) => Field(f, ty.try_fold_with(folder)?),
185+
OpaqueCast(ty) => OpaqueCast(ty.try_fold_with(folder)?),
185186
Index(v) => Index(v.try_fold_with(folder)?),
186187
Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
187188
ConstantIndex { offset, min_length, from_end } => {

Diff for: compiler/rustc_middle/src/mir/visit.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,11 @@ macro_rules! visit_place_fns {
10641064
self.visit_ty(&mut new_ty, TyContext::Location(location));
10651065
if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
10661066
}
1067+
PlaceElem::OpaqueCast(ty) => {
1068+
let mut new_ty = ty;
1069+
self.visit_ty(&mut new_ty, TyContext::Location(location));
1070+
if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
1071+
}
10671072
PlaceElem::Deref
10681073
| PlaceElem::ConstantIndex { .. }
10691074
| PlaceElem::Subslice { .. }
@@ -1133,7 +1138,7 @@ macro_rules! visit_place_fns {
11331138
location: Location,
11341139
) {
11351140
match elem {
1136-
ProjectionElem::Field(_field, ty) => {
1141+
ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
11371142
self.visit_ty(ty, TyContext::Location(location));
11381143
}
11391144
ProjectionElem::Index(local) => {

0 commit comments

Comments
 (0)