Skip to content

Commit

Permalink
Perform OpaqueCast field projection on HIR, too.
Browse files Browse the repository at this point in the history
This is necessary for closure captures in 2021 edition, as they capture individual fields, not the full mentioned variables. So it may try to capture a field of an opaque (because the hidden type is known to be something with a field).
  • Loading branch information
oli-obk committed Jul 24, 2023
1 parent d14569b commit e390dc9
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 0 deletions.
9 changes: 9 additions & 0 deletions compiler/rustc_hir_typeck/src/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,16 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
ty: Ty<'tcx>,
kind: ProjectionKind,
) -> PlaceWithHirId<'tcx> {
let place_ty = base_place.place.ty();
let mut projections = base_place.place.projections;

let node_ty = self.typeck_results.node_type(node.hir_id());
// Opaque types can't have field projections, but we can instead convert
// the current place in-place (heh) to the hidden type, and then apply all
// follow up projections on that.
if node_ty != place_ty && place_ty.has_opaque_types() {
projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
}
projections.push(Projection { kind, ty });
PlaceWithHirId::new(
node.hir_id(),
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match (p1.kind, p2.kind) {
// Paths are the same, continue to next loop.
(ProjectionKind::Deref, ProjectionKind::Deref) => {}
(ProjectionKind::OpaqueCast, ProjectionKind::OpaqueCast) => {}
(ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
if i1 == i2 => {}

Expand All @@ -695,10 +696,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
l @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
| ProjectionKind::OpaqueCast
| ProjectionKind::Field(..)),
r @ (ProjectionKind::Index
| ProjectionKind::Subslice
| ProjectionKind::Deref
| ProjectionKind::OpaqueCast
| ProjectionKind::Field(..)),
) => bug!(
"ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
Expand Down Expand Up @@ -1885,6 +1888,7 @@ fn restrict_capture_precision(
return (place, curr_mode);
}
ProjectionKind::Deref => {}
ProjectionKind::OpaqueCast => {}
ProjectionKind::Field(..) => {} // ignore
}
}
Expand Down Expand Up @@ -1941,6 +1945,7 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String
ProjectionKind::Deref => String::from("Deref"),
ProjectionKind::Index => String::from("Index"),
ProjectionKind::Subslice => String::from("Subslice"),
ProjectionKind::OpaqueCast => String::from("OpaqueCast"),
};
if i != 0 {
projections_str.push(',');
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/hir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ pub enum ProjectionKind {

/// A subslice covering a range of values like `B[x..y]`.
Subslice,

/// A conversion from an opaque type to its hidden type so we can
/// do further projections on it.
OpaqueCast,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/ty/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ impl<'tcx> CapturedPlace<'tcx> {
// Ignore derefs for now, as they are likely caused by
// autoderefs that don't appear in the original code.
HirProjectionKind::Deref => {}
// Just change the type to the hidden type, so we can actually project.
HirProjectionKind::OpaqueCast => {}
proj => bug!("Unexpected projection {:?} in captured place", proj),
}
ty = proj.ty;
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_mir_build/src/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ fn strip_prefix<'a, 'tcx>(
}
assert_matches!(iter.next(), Some(ProjectionElem::Field(..)));
}
HirProjectionKind::OpaqueCast => {
assert_matches!(iter.next(), Some(ProjectionElem::OpaqueCast(..)));
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
bug!("unexpected projection kind: {:?}", projection);
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,9 @@ impl<'tcx> Cx<'tcx> {
variant_index,
name: field,
},
HirProjectionKind::OpaqueCast => {
ExprKind::Use { source: self.thir.exprs.push(captured_place_expr) }
}
HirProjectionKind::Index | HirProjectionKind::Subslice => {
// We don't capture these projections, so we can ignore them here
continue;
Expand Down
2 changes: 2 additions & 0 deletions src/tools/clippy/clippy_utils/src/sugg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,8 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> {
},
// note: unable to trigger `Subslice` kind in tests
ProjectionKind::Subslice => (),
// Doesn't have surface syntax. Only occurs in patterns.
ProjectionKind::OpaqueCast => (),
ProjectionKind::Deref => {
// Explicit derefs are typically handled later on, but
// some items do not need explicit deref, such as array accesses,
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/type-alias-impl-trait/issue-96572-unconstrained.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![feature(type_alias_impl_trait)]
// check-pass
// revisions: default edition2021
//[edition2021] compile-flags: --edition 2021

fn main() {
type T = impl Copy;
Expand Down

0 comments on commit e390dc9

Please sign in to comment.