Skip to content

Commit 9bf9fe0

Browse files
Don't leak inference variables in array unsizing
1 parent 012910d commit 9bf9fe0

File tree

2 files changed

+29
-22
lines changed

2 files changed

+29
-22
lines changed

compiler/rustc_typeck/src/check/method/confirm.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
149149
// time writing the results into the various typeck results.
150150
let mut autoderef =
151151
self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
152-
let (_, n) = match autoderef.nth(pick.autoderefs) {
152+
let (ty, n) = match autoderef.nth(pick.autoderefs) {
153153
Some(n) => n,
154154
None => {
155155
return self.tcx.ty_error_with_message(
@@ -161,14 +161,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
161161
assert_eq!(n, pick.autoderefs);
162162

163163
let mut adjustments = self.adjust_steps(&autoderef);
164+
let mut target = self.structurally_resolved_type(autoderef.span(), ty);
164165

165-
let mut target =
166-
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
167-
168-
match &pick.autoref_or_ptr_adjustment {
166+
match pick.autoref_or_ptr_adjustment {
169167
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
170168
let region = self.next_region_var(infer::Autoref(self.span));
171-
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target });
169+
// Type we're wrapping in a reference, used later for unsizing
170+
let base_ty = target;
171+
172+
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
172173
let mutbl = match mutbl {
173174
hir::Mutability::Not => AutoBorrowMutability::Not,
174175
hir::Mutability::Mut => AutoBorrowMutability::Mut {
@@ -182,10 +183,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
182183
target,
183184
});
184185

185-
if let Some(unsize_target) = unsize {
186+
if unsize {
187+
let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
188+
self.tcx.mk_slice(elem_ty)
189+
} else {
190+
bug!(
191+
"AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
192+
base_ty
193+
)
194+
};
186195
target = self
187196
.tcx
188-
.mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsize_target });
197+
.mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
189198
adjustments
190199
.push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
191200
}

compiler/rustc_typeck/src/check/method/probe.rs

+12-14
Original file line numberDiff line numberDiff line change
@@ -167,26 +167,26 @@ enum ProbeResult {
167167
/// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do
168168
/// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with
169169
/// `mut`), or it has type `*mut T` and we convert it to `*const T`.
170-
#[derive(Debug, PartialEq, Clone)]
171-
pub enum AutorefOrPtrAdjustment<'tcx> {
170+
#[derive(Debug, PartialEq, Copy, Clone)]
171+
pub enum AutorefOrPtrAdjustment {
172172
/// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
173173
/// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
174174
Autoref {
175175
mutbl: hir::Mutability,
176176

177-
/// Indicates that the source expression should be "unsized" to a target type. This should
178-
/// probably eventually go away in favor of just coercing method receivers.
179-
unsize: Option<Ty<'tcx>>,
177+
/// Indicates that the source expression should be "unsized" to a target type.
178+
/// This is special-cased for just arrays unsizing to slices.
179+
unsize: bool,
180180
},
181181
/// Receiver has type `*mut T`, convert to `*const T`
182182
ToConstPtr,
183183
}
184184

185-
impl<'tcx> AutorefOrPtrAdjustment<'tcx> {
186-
fn get_unsize(&self) -> Option<Ty<'tcx>> {
185+
impl AutorefOrPtrAdjustment {
186+
fn get_unsize(&self) -> bool {
187187
match self {
188188
AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
189-
AutorefOrPtrAdjustment::ToConstPtr => None,
189+
AutorefOrPtrAdjustment::ToConstPtr => false,
190190
}
191191
}
192192
}
@@ -204,7 +204,7 @@ pub struct Pick<'tcx> {
204204

205205
/// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
206206
/// `*mut T`, convert it to `*const T`.
207-
pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment<'tcx>>,
207+
pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
208208
pub self_ty: Ty<'tcx>,
209209
}
210210

@@ -1202,7 +1202,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12021202
pick.autoderefs += 1;
12031203
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
12041204
mutbl,
1205-
unsize: pick.autoref_or_ptr_adjustment.and_then(|a| a.get_unsize()),
1205+
unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
12061206
})
12071207
}
12081208

@@ -1227,10 +1227,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12271227
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
12281228
r.map(|mut pick| {
12291229
pick.autoderefs = step.autoderefs;
1230-
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
1231-
mutbl,
1232-
unsize: step.unsize.then_some(self_ty),
1233-
});
1230+
pick.autoref_or_ptr_adjustment =
1231+
Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize });
12341232
pick
12351233
})
12361234
})

0 commit comments

Comments
 (0)