Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ICEs related to Deref<Target=[T; N]> on newtypes #92640

Merged
merged 3 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
// FIXME: perf problem described in #55921.
ui = ty::UniverseIndex::ROOT;
return self.canonicalize_const_var(
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
ct,
);
}
Expand Down
7 changes: 2 additions & 5 deletions compiler/rustc_infer/src/infer/canonical/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
}

CanonicalVarKind::Const(ui) => self
CanonicalVarKind::Const(ui, ty) => self
.next_const_var_in_universe(
self.next_ty_var_in_universe(
TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span },
universe_map(ui),
),
ty,
ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
universe_map(ui),
)
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/infer/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

use crate::infer::MemberConstraint;
use crate::ty::subst::GenericArg;
use crate::ty::{self, BoundVar, List, Region, TyCtxt};
use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use smallvec::SmallVec;
Expand Down Expand Up @@ -104,7 +104,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
CanonicalVarKind::PlaceholderTy(_) => false,
CanonicalVarKind::Region(_) => true,
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(_) => true,
CanonicalVarKind::Const(..) => true,
CanonicalVarKind::PlaceholderConst(_) => false,
}
}
Expand All @@ -130,7 +130,7 @@ pub enum CanonicalVarKind<'tcx> {
PlaceholderRegion(ty::PlaceholderRegion),

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

/// A "placeholder" that represents "any const".
PlaceholderConst(ty::PlaceholderConst<'tcx>),
Expand All @@ -147,7 +147,7 @@ impl<'tcx> CanonicalVarKind<'tcx> {
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
CanonicalVarKind::Const(ui) => ui,
CanonicalVarKind::Const(ui, _) => ui,
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
}
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_traits/src/chalk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ crate fn evaluate_goal<'tcx>(
chalk_ir::VariableKind::Lifetime,
chalk_ir::UniverseIndex { counter: ui.index() },
),
CanonicalVarKind::Const(_ui) => unimplemented!(),
CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
}),
),
Expand Down Expand Up @@ -127,9 +127,9 @@ crate fn evaluate_goal<'tcx>(
chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
ty::UniverseIndex::from_usize(var.skip_kind().counter),
),
chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
ty::UniverseIndex::from_usize(var.skip_kind().counter),
),
// FIXME(compiler-errors): We don't currently have a way of turning
// a Chalk ty back into a rustc ty, right?
chalk_ir::VariableKind::Const(_) => todo!(),
jackh726 marked this conversation as resolved.
Show resolved Hide resolved
};
CanonicalVarInfo { kind }
})
Expand Down
25 changes: 17 additions & 8 deletions compiler/rustc_typeck/src/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaict autoderef.final_ty is identical to the type returned by autoderef.nth, so this was a bit redundant


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 {
Expand All @@ -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 });
}
Expand Down
26 changes: 12 additions & 14 deletions compiler/rustc_typeck/src/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
}
Expand All @@ -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>,
}

Expand Down Expand Up @@ -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()),
})
}

Expand All @@ -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
})
})
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/autoref-autoderef/deref-into-array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// check-pass

struct Test<T>([T; 1]);

impl<T> std::ops::Deref for Test<T> {
type Target = [T; 1];

fn deref(&self) -> &[T; 1] {
&self.0
}
}

fn main() {
let out = Test([(); 1]);
let blah = out.len();
println!("{}", blah);
}
27 changes: 27 additions & 0 deletions src/test/ui/const-generics/deref-into-array-generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// check-pass

struct Test<T, const N: usize>([T; N]);

impl<T: Copy + Default, const N: usize> Default for Test<T, N> {
fn default() -> Self {
Self([T::default(); N])
}
}

impl<T, const N: usize> std::ops::Deref for Test<T, N> {
type Target = [T; N];

fn deref(&self) -> &[T; N] {
&self.0
}
}

fn test() -> Test<u64, 16> {
let test = Test::default();
println!("{}", test.len());
test
}

fn main() {
test();
}