Rollup merge of #114022 - oli-obk:tait_ice_alias_field_projection, r=cjgillot
Perform OpaqueCast field projection on HIR, too. fixes #105819 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). See https://github.com/rust-lang/rust/pull/99806 for when and why we added OpaqueCast to MIR.
This commit is contained in:
commit
576bf82702
@ -498,14 +498,13 @@ fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
|
||||
/// Checks that the types internal to the `place` match up with
|
||||
/// what would be expected.
|
||||
#[instrument(level = "debug", skip(self, location), ret)]
|
||||
fn sanitize_place(
|
||||
&mut self,
|
||||
place: &Place<'tcx>,
|
||||
location: Location,
|
||||
context: PlaceContext,
|
||||
) -> PlaceTy<'tcx> {
|
||||
debug!("sanitize_place: {:?}", place);
|
||||
|
||||
let mut place_ty = PlaceTy::from_ty(self.body().local_decls[place.local].ty);
|
||||
|
||||
for elem in place.projection.iter() {
|
||||
@ -608,7 +607,7 @@ fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Locatio
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
#[instrument(skip(self, location), ret, level = "debug")]
|
||||
fn sanitize_projection(
|
||||
&mut self,
|
||||
base: PlaceTy<'tcx>,
|
||||
@ -617,7 +616,6 @@ fn sanitize_projection(
|
||||
location: Location,
|
||||
context: PlaceContext,
|
||||
) -> PlaceTy<'tcx> {
|
||||
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
|
||||
let tcx = self.tcx();
|
||||
let base_ty = base.ty;
|
||||
match pi {
|
||||
|
@ -198,13 +198,14 @@ pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
|
||||
}
|
||||
|
||||
/// Like `pat_ty`, but ignores implicit `&` patterns.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
|
||||
let base_ty = self.node_ty(pat.hir_id)?;
|
||||
debug!("pat_ty(pat={:?}) base_ty={:?}", pat, base_ty);
|
||||
trace!(?base_ty);
|
||||
|
||||
// This code detects whether we are looking at a `ref x`,
|
||||
// and if so, figures out what the type *being borrowed* is.
|
||||
let ret_ty = match pat.kind {
|
||||
match pat.kind {
|
||||
PatKind::Binding(..) => {
|
||||
let bm = *self
|
||||
.typeck_results
|
||||
@ -217,21 +218,18 @@ fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
|
||||
// but what we want here is the type of the underlying value being borrowed.
|
||||
// So peel off one-level, turning the &T into T.
|
||||
match base_ty.builtin_deref(false) {
|
||||
Some(t) => t.ty,
|
||||
Some(t) => Ok(t.ty),
|
||||
None => {
|
||||
debug!("By-ref binding of non-derefable type {:?}", base_ty);
|
||||
return Err(());
|
||||
debug!("By-ref binding of non-derefable type");
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base_ty
|
||||
Ok(base_ty)
|
||||
}
|
||||
}
|
||||
_ => base_ty,
|
||||
};
|
||||
debug!("pat_ty(pat={:?}) ret_ty={:?}", pat, ret_ty);
|
||||
|
||||
Ok(ret_ty)
|
||||
_ => Ok(base_ty),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
@ -299,13 +297,11 @@ fn cat_expr_adjusted_with<F>(
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub(crate) fn cat_expr_unadjusted(
|
||||
&self,
|
||||
expr: &hir::Expr<'_>,
|
||||
) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
debug!("cat_expr: id={} expr={:?}", expr.hir_id, expr);
|
||||
|
||||
let expr_ty = self.expr_ty(expr)?;
|
||||
match expr.kind {
|
||||
hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => {
|
||||
@ -319,7 +315,7 @@ pub(crate) fn cat_expr_unadjusted(
|
||||
|
||||
hir::ExprKind::Field(ref base, _) => {
|
||||
let base = self.cat_expr(base)?;
|
||||
debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
|
||||
debug!(?base);
|
||||
|
||||
let field_idx = self
|
||||
.typeck_results
|
||||
@ -389,7 +385,7 @@ pub(crate) fn cat_expr_unadjusted(
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, span))]
|
||||
#[instrument(level = "debug", skip(self, span), ret)]
|
||||
pub(crate) fn cat_res(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
@ -430,6 +426,7 @@ pub(crate) fn cat_res(
|
||||
/// Note: the actual upvar access contains invisible derefs of closure
|
||||
/// environment and upvar reference as appropriate. Only regionck cares
|
||||
/// about these dereferences, so we let it compute them as needed.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWithHirId<'tcx>> {
|
||||
let closure_expr_def_id = self.body_owner;
|
||||
|
||||
@ -439,24 +436,20 @@ fn cat_upvar(&self, hir_id: hir::HirId, var_id: hir::HirId) -> McResult<PlaceWit
|
||||
};
|
||||
let var_ty = self.node_ty(var_id)?;
|
||||
|
||||
let ret = PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new());
|
||||
|
||||
debug!("cat_upvar ret={:?}", ret);
|
||||
Ok(ret)
|
||||
Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub(crate) fn cat_rvalue(
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
expr_ty: Ty<'tcx>,
|
||||
) -> PlaceWithHirId<'tcx> {
|
||||
debug!("cat_rvalue hir_id={:?}, expr_ty={:?}, span={:?}", hir_id, expr_ty, span);
|
||||
let ret = PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new());
|
||||
debug!("cat_rvalue ret={:?}", ret);
|
||||
ret
|
||||
PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, node), ret)]
|
||||
pub(crate) fn cat_projection<N: HirNode>(
|
||||
&self,
|
||||
node: &N,
|
||||
@ -464,16 +457,23 @@ pub(crate) fn cat_projection<N: HirNode>(
|
||||
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 });
|
||||
let ret = PlaceWithHirId::new(
|
||||
PlaceWithHirId::new(
|
||||
node.hir_id(),
|
||||
base_place.place.base_ty,
|
||||
base_place.place.base,
|
||||
projections,
|
||||
);
|
||||
debug!("cat_field ret {:?}", ret);
|
||||
ret
|
||||
)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
@ -497,7 +497,7 @@ fn cat_overloaded_place(
|
||||
self.cat_deref(expr, base)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, node))]
|
||||
#[instrument(level = "debug", skip(self, node), ret)]
|
||||
fn cat_deref(
|
||||
&self,
|
||||
node: &impl HirNode,
|
||||
@ -514,14 +514,12 @@ fn cat_deref(
|
||||
let mut projections = base_place.place.projections;
|
||||
projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
|
||||
|
||||
let ret = PlaceWithHirId::new(
|
||||
Ok(PlaceWithHirId::new(
|
||||
node.hir_id(),
|
||||
base_place.place.base_ty,
|
||||
base_place.place.base,
|
||||
projections,
|
||||
);
|
||||
debug!("cat_deref ret {:?}", ret);
|
||||
Ok(ret)
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn cat_pattern<F>(
|
||||
@ -603,6 +601,13 @@ fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult<
|
||||
}
|
||||
}
|
||||
|
||||
/// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
|
||||
/// is being matched against.
|
||||
///
|
||||
/// In general, the way that this works is that we walk down the pattern,
|
||||
/// constructing a `PlaceWithHirId` that represents the path that will be taken
|
||||
/// to reach the value being matched.
|
||||
#[instrument(skip(self, op), ret, level = "debug")]
|
||||
fn cat_pattern_<F>(
|
||||
&self,
|
||||
mut place_with_id: PlaceWithHirId<'tcx>,
|
||||
@ -612,15 +617,6 @@ fn cat_pattern_<F>(
|
||||
where
|
||||
F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
|
||||
{
|
||||
// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
|
||||
// is being matched against.
|
||||
//
|
||||
// In general, the way that this works is that we walk down the pattern,
|
||||
// constructing a `PlaceWithHirId` that represents the path that will be taken
|
||||
// to reach the value being matched.
|
||||
|
||||
debug!("cat_pattern(pat={:?}, place_with_id={:?})", pat, place_with_id);
|
||||
|
||||
// If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
|
||||
// `PlaceWithHirId`s are constructed differently from patterns. For example, in
|
||||
//
|
||||
@ -654,11 +650,11 @@ fn cat_pattern_<F>(
|
||||
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
|
||||
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
|
||||
for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) {
|
||||
debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
|
||||
debug!("applying adjustment to place_with_id={:?}", place_with_id);
|
||||
place_with_id = self.cat_deref(pat, place_with_id)?;
|
||||
}
|
||||
let place_with_id = place_with_id; // lose mutability
|
||||
debug!("cat_pattern: applied adjustment derefs to get place_with_id={:?}", place_with_id);
|
||||
debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
|
||||
|
||||
// Invoke the callback, but only now, after the `place_with_id` has adjusted.
|
||||
//
|
||||
|
@ -264,12 +264,12 @@ fn analyze_closure(
|
||||
self.demand_eqtype(span, closure_kind.to_ty(self.tcx), closure_kind_ty);
|
||||
|
||||
// If we have an origin, store it.
|
||||
if let Some(origin) = origin {
|
||||
let origin = if enable_precise_capture(span) {
|
||||
(origin.0, origin.1)
|
||||
} else {
|
||||
(origin.0, Place { projections: vec![], ..origin.1 })
|
||||
};
|
||||
if let Some(mut origin) = origin {
|
||||
if !enable_precise_capture(span) {
|
||||
// Without precise captures, we just capture the base and ignore
|
||||
// the projections.
|
||||
origin.1.projections.clear()
|
||||
}
|
||||
|
||||
self.typeck_results
|
||||
.borrow_mut()
|
||||
@ -294,10 +294,7 @@ fn analyze_closure(
|
||||
|
||||
// Equate the type variables for the upvars with the actual types.
|
||||
let final_upvar_tys = self.final_upvar_tys(closure_def_id);
|
||||
debug!(
|
||||
"analyze_closure: id={:?} args={:?} final_upvar_tys={:?}",
|
||||
closure_hir_id, args, final_upvar_tys
|
||||
);
|
||||
debug!(?closure_hir_id, ?args, ?final_upvar_tys);
|
||||
|
||||
// Build a tuple (U0..Un) of the final upvar types U0..Un
|
||||
// and unify the upvar tuple type in the closure with it:
|
||||
@ -338,10 +335,7 @@ fn final_upvar_tys(&self, closure_id: LocalDefId) -> Vec<Ty<'tcx>> {
|
||||
let upvar_ty = captured_place.place.ty();
|
||||
let capture = captured_place.info.capture_kind;
|
||||
|
||||
debug!(
|
||||
"final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
|
||||
captured_place.place, upvar_ty, capture, captured_place.mutability,
|
||||
);
|
||||
debug!(?captured_place.place, ?upvar_ty, ?capture, ?captured_place.mutability);
|
||||
|
||||
apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region)
|
||||
})
|
||||
@ -679,6 +673,7 @@ fn compute_min_captures(
|
||||
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 => {}
|
||||
|
||||
@ -701,10 +696,12 @@ fn compute_min_captures(
|
||||
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: ({:?}, {:?})",
|
||||
@ -1890,6 +1887,7 @@ fn restrict_capture_precision(
|
||||
return (place, curr_mode);
|
||||
}
|
||||
ProjectionKind::Deref => {}
|
||||
ProjectionKind::OpaqueCast => {}
|
||||
ProjectionKind::Field(..) => {} // ignore
|
||||
}
|
||||
}
|
||||
@ -1946,6 +1944,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(',');
|
||||
|
@ -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)]
|
||||
|
@ -174,6 +174,8 @@ pub fn to_symbol(&self) -> Symbol {
|
||||
// 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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1072,6 +1072,9 @@ fn convert_captured_hir_place(
|
||||
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;
|
||||
|
@ -1011,6 +1011,8 @@ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
|
||||
},
|
||||
// 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,
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user