Don't leak inference variables in array unsizing

This commit is contained in:
Michael Goulet 2022-01-07 01:23:07 -08:00
parent 012910dab2
commit 9bf9fe07dc
2 changed files with 29 additions and 22 deletions

View File

@ -149,7 +149,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
// time writing the results into the various typeck results.
let mut autoderef =
self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
let (_, n) = match autoderef.nth(pick.autoderefs) {
let (ty, n) = match autoderef.nth(pick.autoderefs) {
Some(n) => n,
None => {
return self.tcx.ty_error_with_message(
@ -161,14 +161,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
assert_eq!(n, pick.autoderefs);
let mut adjustments = self.adjust_steps(&autoderef);
let mut target = self.structurally_resolved_type(autoderef.span(), ty);
let mut target =
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
match &pick.autoref_or_ptr_adjustment {
match pick.autoref_or_ptr_adjustment {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
let region = self.next_region_var(infer::Autoref(self.span));
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target });
// Type we're wrapping in a reference, used later for unsizing
let base_ty = target;
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
let mutbl = match mutbl {
hir::Mutability::Not => AutoBorrowMutability::Not,
hir::Mutability::Mut => AutoBorrowMutability::Mut {
@ -182,10 +183,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
target,
});
if let Some(unsize_target) = unsize {
if unsize {
let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
self.tcx.mk_slice(elem_ty)
} else {
bug!(
"AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
base_ty
)
};
target = self
.tcx
.mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsize_target });
.mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
adjustments
.push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
}

View File

@ -167,26 +167,26 @@ enum ProbeResult {
/// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do
/// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with
/// `mut`), or it has type `*mut T` and we convert it to `*const T`.
#[derive(Debug, PartialEq, Clone)]
pub enum AutorefOrPtrAdjustment<'tcx> {
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum AutorefOrPtrAdjustment {
/// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
/// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
Autoref {
mutbl: hir::Mutability,
/// Indicates that the source expression should be "unsized" to a target type. This should
/// probably eventually go away in favor of just coercing method receivers.
unsize: Option<Ty<'tcx>>,
/// Indicates that the source expression should be "unsized" to a target type.
/// This is special-cased for just arrays unsizing to slices.
unsize: bool,
},
/// Receiver has type `*mut T`, convert to `*const T`
ToConstPtr,
}
impl<'tcx> AutorefOrPtrAdjustment<'tcx> {
fn get_unsize(&self) -> Option<Ty<'tcx>> {
impl AutorefOrPtrAdjustment {
fn get_unsize(&self) -> bool {
match self {
AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
AutorefOrPtrAdjustment::ToConstPtr => None,
AutorefOrPtrAdjustment::ToConstPtr => false,
}
}
}
@ -204,7 +204,7 @@ pub struct Pick<'tcx> {
/// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
/// `*mut T`, convert it to `*const T`.
pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment<'tcx>>,
pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
pub self_ty: Ty<'tcx>,
}
@ -1202,7 +1202,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
pick.autoderefs += 1;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
mutbl,
unsize: pick.autoref_or_ptr_adjustment.and_then(|a| a.get_unsize()),
unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
})
}
@ -1227,10 +1227,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
mutbl,
unsize: step.unsize.then_some(self_ty),
});
pick.autoref_or_ptr_adjustment =
Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize });
pick
})
})