diff options
| author | Michael Goulet <michael@errs.io> | 2022-01-07 01:23:07 -0800 |
|---|---|---|
| committer | Michael Goulet <michael@errs.io> | 2022-01-12 08:28:41 -0800 |
| commit | 9bf9fe07dc2775a8499326990a2fa4bc4af88f8f (patch) | |
| tree | c80c8e87704529ff4babefc13acf7a28893992da | |
| parent | 012910dab253e8b64dd06e2a91de1943d518439b (diff) | |
| download | rust-9bf9fe07dc2775a8499326990a2fa4bc4af88f8f.tar.gz rust-9bf9fe07dc2775a8499326990a2fa4bc4af88f8f.zip | |
Don't leak inference variables in array unsizing
| -rw-r--r-- | compiler/rustc_typeck/src/check/method/confirm.rs | 25 | ||||
| -rw-r--r-- | compiler/rustc_typeck/src/check/method/probe.rs | 26 |
2 files changed, 29 insertions, 22 deletions
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index dabfe92190b..27c39934ba8 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -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 }); } diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 5615a08369d..8ce1c27f81d 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -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 }) }) |
