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

Implement Deref<Target = [T]> for [T; N], and fix const infer variable canonicalization (fix Deref<Target=[T; N]> ICEs) #92652

Closed
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
1 change: 0 additions & 1 deletion compiler/rustc_middle/src/traits/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ pub struct CandidateStep<'tcx> {
/// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
/// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
pub from_unsafe_deref: bool,
pub unsize: bool,
}

#[derive(Clone, Debug, HashStable)]
Expand Down
36 changes: 31 additions & 5 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ impl<'tcx> Cx<'tcx> {
ExprKind::Deref { arg: self.thir.exprs.push(expr) }
}
Adjust::Deref(Some(deref)) => {
// We don't need to do call adjust_span here since
// deref coercions always start with a built-in deref.
let call = deref.method_call(self.tcx(), expr.ty);
let source_ty = expr.ty;

expr = Expr {
temp_lifetime,
Expand All @@ -140,9 +138,37 @@ impl<'tcx> Cx<'tcx> {
},
};

let expr = Box::new([self.thir.exprs.push(expr)]);
let deref_arg_expr = self.thir.exprs.push(expr);

self.overloaded_place(hir_expr, adjustment.target, Some(call), expr, deref.span)
// FIXME: this is a hack to allow us to evaluate `<[T; N]>::deref` as const, since
// it's really just a pointer unsize from `&[T; N]` -> `&[T]`
Comment on lines +143 to +144
Copy link
Member Author

Choose a reason for hiding this comment

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

This is the only part of the PR I am somewhat unhappy with, but it works.

if let ty::Array(elem_ty, _) = source_ty.kind() {
expr = Expr {
temp_lifetime,
ty: self.tcx.mk_ref(
deref.region,
ty::TypeAndMut { ty: self.tcx.mk_slice(elem_ty), mutbl: deref.mutbl },
),
span,
kind: ExprKind::Pointer {
cast: PointerCast::Unsize,
source: deref_arg_expr,
},
};
ExprKind::Deref { arg: self.thir.exprs.push(expr) }
} else {
// We don't need to do call adjust_span here since
// deref coercions always start with a built-in deref.
let call = deref.method_call(self.tcx(), source_ty);

self.overloaded_place(
hir_expr,
adjustment.target,
Some(call),
Box::new([deref_arg_expr]),
deref.span,
)
}
}
Adjust::Borrow(AutoBorrow::Ref(_, m)) => ExprKind::Borrow {
borrow_kind: m.to_borrow_kind(),
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!(),
};
CanonicalVarInfo { kind }
})
Expand Down
10 changes: 1 addition & 9 deletions compiler/rustc_typeck/src/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));

match &pick.autoref_or_ptr_adjustment {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl }) => {
let region = self.next_region_var(infer::Autoref(self.span));
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target });
let mutbl = match mutbl {
Expand All @@ -181,14 +181,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
target,
});

if let Some(unsize_target) = unsize {
target = self
.tcx
.mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsize_target });
adjustments
.push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
}
}
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
target = match target.kind() {
Expand Down
64 changes: 7 additions & 57 deletions compiler/rustc_typeck/src/check/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,29 +168,13 @@ enum ProbeResult {
/// (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> {
/// 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>>,
},
pub enum AutorefOrPtrAdjustment {
/// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`)
Autoref { mutbl: hir::Mutability },
/// Receiver has type `*mut T`, convert to `*const T`
ToConstPtr,
}

impl<'tcx> AutorefOrPtrAdjustment<'tcx> {
fn get_unsize(&self) -> Option<Ty<'tcx>> {
match self {
AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
AutorefOrPtrAdjustment::ToConstPtr => None,
}
}
}

#[derive(Debug, PartialEq, Clone)]
pub struct Pick<'tcx> {
pub item: ty::AssocItem,
Expand All @@ -204,7 +188,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 @@ -371,7 +355,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
),
autoderefs: 0,
from_unsafe_deref: false,
unsize: false,
}]),
opt_bad_ty: None,
reached_recursion_limit: false,
Expand Down Expand Up @@ -483,7 +466,7 @@ fn method_autoderef_steps<'tcx>(
.include_raw_pointers()
.silence_errors();
let mut reached_raw_pointer = false;
let mut steps: Vec<_> = autoderef
let steps: Vec<_> = autoderef
.by_ref()
.map(|(ty, d)| {
let step = CandidateStep {
Expand All @@ -493,7 +476,6 @@ fn method_autoderef_steps<'tcx>(
),
autoderefs: d,
from_unsafe_deref: reached_raw_pointer,
unsize: false,
};
if let ty::RawPtr(_) = ty.kind() {
// all the subsequent steps will be from_unsafe_deref
Expand All @@ -510,23 +492,6 @@ fn method_autoderef_steps<'tcx>(
ty: infcx
.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
}),
ty::Array(elem_ty, _) => {
let dereferences = steps.len() - 1;

steps.push(CandidateStep {
self_ty: infcx.make_query_response_ignoring_pending_obligations(
inference_vars,
infcx.tcx.mk_slice(elem_ty),
),
autoderefs: dereferences,
// this could be from an unsafe deref if we had
// a *mut/const [T; N]
from_unsafe_deref: reached_raw_pointer,
unsize: true,
});

None
}
_ => None,
};

Expand Down Expand Up @@ -1189,21 +1154,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self_ty: Ty<'tcx>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
if step.unsize {
return None;
}

self.pick_method(self_ty, unstable_candidates).map(|r| {
r.map(|mut pick| {
pick.autoderefs = step.autoderefs;

// Insert a `&*` or `&mut *` if this is a reference type:
if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() {
pick.autoderefs += 1;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
mutbl,
unsize: pick.autoref_or_ptr_adjustment.and_then(|a| a.get_unsize()),
})
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref { mutbl })
}

pick
Expand All @@ -1227,10 +1185,7 @@ 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 });
pick
})
})
Expand All @@ -1245,11 +1200,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
self_ty: Ty<'tcx>,
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
) -> Option<PickResult<'tcx>> {
// Don't convert an unsized reference to ptr
if step.unsize {
return None;
}

let ty = match self_ty.kind() {
ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) => ty,
_ => return None,
Expand Down
24 changes: 24 additions & 0 deletions library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ use crate::mem::{self, MaybeUninit};
use crate::ops::{
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
};
#[cfg(not(bootstrap))]
use crate::ops::{Deref, DerefMut};
use crate::slice::{Iter, IterMut};

mod equality;
Expand Down Expand Up @@ -301,6 +303,28 @@ where
}
}

#[stable(feature = "deref_on_arrays", since = "1.60.0")]
#[rustc_const_unstable(feature = "const_deref_on_arrays", issue = "none")]
#[cfg(not(bootstrap))]
impl<T, const N: usize> const Deref for [T; N] {
type Target = [T];

#[inline]
fn deref(&self) -> &Self::Target {
self as &[T]
}
}

#[stable(feature = "deref_on_arrays", since = "1.60.0")]
#[rustc_const_unstable(feature = "const_deref_on_arrays", issue = "none")]
#[cfg(not(bootstrap))]
impl<T, const N: usize> const DerefMut for [T; N] {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self as &mut [T]
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd, const N: usize> PartialOrd for [T; N] {
#[inline]
Expand Down
Loading