Skip to content

Commit cb5ecff

Browse files
authored
Rollup merge of #92640 - compiler-errors:array-deref-on-newtype, r=lcnr
Fix ICEs related to `Deref<Target=[T; N]>` on newtypes 1. Stash a const infer's type into the canonical var during canonicalization, so we can recreate the fresh const infer with that same type. For example, given `[T; _]` we know `_` is a `usize`. If we go from infer => canonical => infer, we shouldn't forget that variable is a usize. Fixes #92626 Fixes #83704 2. Don't stash the autoderef'd slice type that we get from method lookup, but instead recreate it during method confirmation. We need to do this because the type we receive back after picking the method references a type variable that does not exist after probing is done. Fixes #92637 ... A better solution for the second issue would be to actually _properly_ implement `Deref` for `[T; N]` instead of fixing this autoderef hack to stop leaking inference variables. But I actually looked into this, and there are many complications with const impls.
2 parents d501ead + 7bf0cb7 commit cb5ecff

File tree

8 files changed

+84
-36
lines changed

8 files changed

+84
-36
lines changed

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
425425
// FIXME: perf problem described in #55921.
426426
ui = ty::UniverseIndex::ROOT;
427427
return self.canonicalize_const_var(
428-
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
428+
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
429429
ct,
430430
);
431431
}

compiler/rustc_infer/src/infer/canonical/mod.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
137137
self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
138138
}
139139

140-
CanonicalVarKind::Const(ui) => self
140+
CanonicalVarKind::Const(ui, ty) => self
141141
.next_const_var_in_universe(
142-
self.next_ty_var_in_universe(
143-
TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span },
144-
universe_map(ui),
145-
),
142+
ty,
146143
ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
147144
universe_map(ui),
148145
)

compiler/rustc_middle/src/infer/canonical.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
2424
use crate::infer::MemberConstraint;
2525
use crate::ty::subst::GenericArg;
26-
use crate::ty::{self, BoundVar, List, Region, TyCtxt};
26+
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
2727
use rustc_index::vec::IndexVec;
2828
use rustc_macros::HashStable;
2929
use smallvec::SmallVec;
@@ -104,7 +104,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
104104
CanonicalVarKind::PlaceholderTy(_) => false,
105105
CanonicalVarKind::Region(_) => true,
106106
CanonicalVarKind::PlaceholderRegion(..) => false,
107-
CanonicalVarKind::Const(_) => true,
107+
CanonicalVarKind::Const(..) => true,
108108
CanonicalVarKind::PlaceholderConst(_) => false,
109109
}
110110
}
@@ -130,7 +130,7 @@ pub enum CanonicalVarKind<'tcx> {
130130
PlaceholderRegion(ty::PlaceholderRegion),
131131

132132
/// Some kind of const inference variable.
133-
Const(ty::UniverseIndex),
133+
Const(ty::UniverseIndex, Ty<'tcx>),
134134

135135
/// A "placeholder" that represents "any const".
136136
PlaceholderConst(ty::PlaceholderConst<'tcx>),
@@ -147,7 +147,7 @@ impl<'tcx> CanonicalVarKind<'tcx> {
147147
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
148148
CanonicalVarKind::Region(ui) => ui,
149149
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
150-
CanonicalVarKind::Const(ui) => ui,
150+
CanonicalVarKind::Const(ui, _) => ui,
151151
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
152152
}
153153
}

compiler/rustc_traits/src/chalk/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ crate fn evaluate_goal<'tcx>(
8585
chalk_ir::VariableKind::Lifetime,
8686
chalk_ir::UniverseIndex { counter: ui.index() },
8787
),
88-
CanonicalVarKind::Const(_ui) => unimplemented!(),
88+
CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
8989
CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
9090
}),
9191
),
@@ -127,9 +127,9 @@ crate fn evaluate_goal<'tcx>(
127127
chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
128128
ty::UniverseIndex::from_usize(var.skip_kind().counter),
129129
),
130-
chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
131-
ty::UniverseIndex::from_usize(var.skip_kind().counter),
132-
),
130+
// FIXME(compiler-errors): We don't currently have a way of turning
131+
// a Chalk ty back into a rustc ty, right?
132+
chalk_ir::VariableKind::Const(_) => todo!(),
133133
};
134134
CanonicalVarInfo { kind }
135135
})

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

Lines changed: 17 additions & 8 deletions
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

Lines changed: 12 additions & 14 deletions
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
})
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// check-pass
2+
3+
struct Test<T>([T; 1]);
4+
5+
impl<T> std::ops::Deref for Test<T> {
6+
type Target = [T; 1];
7+
8+
fn deref(&self) -> &[T; 1] {
9+
&self.0
10+
}
11+
}
12+
13+
fn main() {
14+
let out = Test([(); 1]);
15+
let blah = out.len();
16+
println!("{}", blah);
17+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// check-pass
2+
3+
struct Test<T, const N: usize>([T; N]);
4+
5+
impl<T: Copy + Default, const N: usize> Default for Test<T, N> {
6+
fn default() -> Self {
7+
Self([T::default(); N])
8+
}
9+
}
10+
11+
impl<T, const N: usize> std::ops::Deref for Test<T, N> {
12+
type Target = [T; N];
13+
14+
fn deref(&self) -> &[T; N] {
15+
&self.0
16+
}
17+
}
18+
19+
fn test() -> Test<u64, 16> {
20+
let test = Test::default();
21+
println!("{}", test.len());
22+
test
23+
}
24+
25+
fn main() {
26+
test();
27+
}

0 commit comments

Comments
 (0)