Skip to content

Commit 8327047

Browse files
committed
Auto merge of #113393 - compiler-errors:next-solver-unsize-rhs, r=lcnr
Normalize the RHS of an `Unsize` goal in the new solver `Unsize` goals are... tricky. Not only do they structurally match on their self type, but they're also structural on their other type parameter. I'm pretty certain that it is both incomplete and also just plain undesirable to not consider normalizing the RHS of an unsize goal. More practically, I'd like for this code to work: ```rust trait A {} trait B: A {} impl A for usize {} impl B for usize {} trait Mirror { type Assoc: ?Sized; } impl<T: ?Sized> Mirror for T { type Assoc = T; } fn main() { // usize: Unsize<dyn B> let x = Box::new(1usize) as Box<<dyn B as Mirror>::Assoc>; // dyn A: Unsize<dyn B> let y = x as Box<<dyn A as Mirror>::Assoc>; } ``` --- In order to achieve this, we add `EvalCtxt::normalize_non_self_ty` (naming modulo bikeshedding), which *must* be used for all non-self type arguments that are structurally matched in candidate assembly. Currently this is only necessary for `Unsize`'s argument, but I could see future traits requiring this (hopefully rarely) in the future. It uses `repeat_while_none` to limit infinite looping, and normalizes the self type until it is no longer an alias. Also, we need to fix feature gate detection for `trait_upcasting` and `unsized_tuple_coercion` when HIR typeck has unnormalized types. We can do that by checking the `ImplSource` returned by selection, which necessitates adding a new impl source for tuple upcasting.
2 parents 4fc6b33 + a7ed9c1 commit 8327047

File tree

27 files changed

+587
-517
lines changed

27 files changed

+587
-517
lines changed

compiler/rustc_const_eval/src/transform/check_consts/check.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt;
88
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
99
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
1010
use rustc_middle::mir::*;
11+
use rustc_middle::traits::BuiltinImplSource;
1112
use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt};
1213
use rustc_middle::ty::{GenericArgKind, GenericArgs};
1314
use rustc_middle::ty::{TraitRef, TypeVisitableExt};
@@ -766,15 +767,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
766767
};
767768

768769
match implsrc {
769-
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
770+
Ok(Some(ImplSource::Param(ty::BoundConstness::ConstIfConst, _))) => {
770771
debug!(
771772
"const_trait_impl: provided {:?} via where-clause in {:?}",
772773
trait_ref, param_env
773774
);
774775
return;
775776
}
776777
// Closure: Fn{Once|Mut}
777-
Ok(Some(ImplSource::Builtin(_)))
778+
Ok(Some(ImplSource::Builtin(BuiltinImplSource::Misc, _)))
778779
if trait_ref.self_ty().is_closure()
779780
&& tcx.fn_trait_kind_from_def_id(trait_id).is_some() =>
780781
{

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_hir::LangItem;
77
use rustc_infer::infer::TyCtxtInferExt;
88
use rustc_middle::mir;
99
use rustc_middle::mir::*;
10+
use rustc_middle::traits::BuiltinImplSource;
1011
use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
1112
use rustc_trait_selection::traits::{
1213
self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
@@ -172,7 +173,8 @@ impl Qualif for NeedsNonConstDrop {
172173

173174
if !matches!(
174175
impl_src,
175-
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
176+
ImplSource::Builtin(BuiltinImplSource::Misc, _)
177+
| ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
176178
) {
177179
// If our const destruct candidate is not ConstDestruct or implied by the param env,
178180
// then it's bad

compiler/rustc_hir_typeck/src/coercion.rs

+31-27
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
4646
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
4747
use rustc_infer::traits::{Obligation, PredicateObligation};
4848
use rustc_middle::lint::in_external_macro;
49+
use rustc_middle::traits::BuiltinImplSource;
4950
use rustc_middle::ty::adjustment::{
5051
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
5152
};
@@ -636,29 +637,14 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
636637
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)))
637638
if traits.contains(&trait_pred.def_id()) =>
638639
{
639-
let trait_pred = self.resolve_vars_if_possible(trait_pred);
640-
if unsize_did == trait_pred.def_id() {
641-
let self_ty = trait_pred.self_ty();
642-
let unsize_ty = trait_pred.trait_ref.args[1].expect_ty();
643-
if let (ty::Dynamic(ref data_a, ..), ty::Dynamic(ref data_b, ..)) =
644-
(self_ty.kind(), unsize_ty.kind())
645-
&& data_a.principal_def_id() != data_b.principal_def_id()
646-
{
647-
debug!("coerce_unsized: found trait upcasting coercion");
648-
has_trait_upcasting_coercion = Some((self_ty, unsize_ty));
649-
}
650-
if let ty::Tuple(..) = unsize_ty.kind() {
651-
debug!("coerce_unsized: found unsized tuple coercion");
652-
has_unsized_tuple_coercion = true;
653-
}
654-
}
655640
trait_pred
656641
}
657642
_ => {
658643
coercion.obligations.push(obligation);
659644
continue;
660645
}
661646
};
647+
let trait_pred = self.resolve_vars_if_possible(trait_pred);
662648
match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) {
663649
// Uncertain or unimplemented.
664650
Ok(None) => {
@@ -701,20 +687,28 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
701687
// be silent, as it causes a type mismatch later.
702688
}
703689

704-
Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()),
690+
Ok(Some(impl_source)) => {
691+
// Some builtin coercions are still unstable so we detect
692+
// these here and emit a feature error if coercion doesn't fail
693+
// due to another reason.
694+
match impl_source {
695+
traits::ImplSource::Builtin(
696+
BuiltinImplSource::TraitUpcasting { .. },
697+
_,
698+
) => {
699+
has_trait_upcasting_coercion =
700+
Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
701+
}
702+
traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
703+
has_unsized_tuple_coercion = true;
704+
}
705+
_ => {}
706+
}
707+
queue.extend(impl_source.nested_obligations())
708+
}
705709
}
706710
}
707711

708-
if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
709-
feature_err(
710-
&self.tcx.sess.parse_sess,
711-
sym::unsized_tuple_coercion,
712-
self.cause.span,
713-
"unsized tuple coercion is not stable enough for use and is subject to change",
714-
)
715-
.emit();
716-
}
717-
718712
if let Some((sub, sup)) = has_trait_upcasting_coercion
719713
&& !self.tcx().features().trait_upcasting
720714
{
@@ -730,6 +724,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
730724
err.emit();
731725
}
732726

727+
if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
728+
feature_err(
729+
&self.tcx.sess.parse_sess,
730+
sym::unsized_tuple_coercion,
731+
self.cause.span,
732+
"unsized tuple coercion is not stable enough for use and is subject to change",
733+
)
734+
.emit();
735+
}
736+
733737
Ok(coercion)
734738
}
735739

compiler/rustc_middle/src/macros.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ macro_rules! span_bug {
4343

4444
#[macro_export]
4545
macro_rules! CloneLiftImpls {
46-
($($ty:ty,)+) => {
46+
($($ty:ty),+ $(,)?) => {
4747
$(
4848
impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
4949
type Lifted = Self;
@@ -59,7 +59,7 @@ macro_rules! CloneLiftImpls {
5959
/// allocated data** (i.e., don't need to be folded).
6060
#[macro_export]
6161
macro_rules! TrivialTypeTraversalImpls {
62-
($($ty:ty,)+) => {
62+
($($ty:ty),+ $(,)?) => {
6363
$(
6464
impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty {
6565
fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<'tcx>>>(

compiler/rustc_middle/src/mir/basic_blocks.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
178178
}
179179
}
180180

181-
TrivialTypeTraversalAndLiftImpls! {
182-
Cache,
183-
}
181+
TrivialTypeTraversalAndLiftImpls! { Cache }
184182

185183
impl<S: Encoder> Encodable<S> for Cache {
186184
#[inline]

compiler/rustc_middle/src/mir/interpret/error.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
6767
}
6868
}
6969

70-
TrivialTypeTraversalAndLiftImpls! {
71-
ErrorHandled,
72-
}
70+
TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
7371

7472
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
7573
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;

compiler/rustc_middle/src/mir/mod.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -706,9 +706,7 @@ pub enum BindingForm<'tcx> {
706706
RefForGuard,
707707
}
708708

709-
TrivialTypeTraversalAndLiftImpls! {
710-
BindingForm<'tcx>,
711-
}
709+
TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
712710

713711
mod binding_form_impl {
714712
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};

compiler/rustc_middle/src/traits/mod.rs

+28-46
Original file line numberDiff line numberDiff line change
@@ -649,43 +649,31 @@ pub enum ImplSource<'tcx, N> {
649649
/// for some type parameter. The `Vec<N>` represents the
650650
/// obligations incurred from normalizing the where-clause (if
651651
/// any).
652-
Param(Vec<N>, ty::BoundConstness),
652+
Param(ty::BoundConstness, Vec<N>),
653653

654-
/// Virtual calls through an object.
655-
Object(ImplSourceObjectData<N>),
656-
657-
/// Successful resolution for a builtin trait.
658-
Builtin(Vec<N>),
659-
660-
/// ImplSource for trait upcasting coercion
661-
TraitUpcasting(ImplSourceTraitUpcastingData<N>),
654+
/// Successful resolution for a builtin impl.
655+
Builtin(BuiltinImplSource, Vec<N>),
662656
}
663657

664658
impl<'tcx, N> ImplSource<'tcx, N> {
665659
pub fn nested_obligations(self) -> Vec<N> {
666660
match self {
667661
ImplSource::UserDefined(i) => i.nested,
668-
ImplSource::Param(n, _) | ImplSource::Builtin(n) => n,
669-
ImplSource::Object(d) => d.nested,
670-
ImplSource::TraitUpcasting(d) => d.nested,
662+
ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n,
671663
}
672664
}
673665

674666
pub fn borrow_nested_obligations(&self) -> &[N] {
675667
match self {
676668
ImplSource::UserDefined(i) => &i.nested,
677-
ImplSource::Param(n, _) | ImplSource::Builtin(n) => &n,
678-
ImplSource::Object(d) => &d.nested,
679-
ImplSource::TraitUpcasting(d) => &d.nested,
669+
ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => &n,
680670
}
681671
}
682672

683673
pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
684674
match self {
685675
ImplSource::UserDefined(i) => &mut i.nested,
686-
ImplSource::Param(n, _) | ImplSource::Builtin(n) => n,
687-
ImplSource::Object(d) => &mut d.nested,
688-
ImplSource::TraitUpcasting(d) => &mut d.nested,
676+
ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n,
689677
}
690678
}
691679

@@ -699,17 +687,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
699687
args: i.args,
700688
nested: i.nested.into_iter().map(f).collect(),
701689
}),
702-
ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
703-
ImplSource::Builtin(n) => ImplSource::Builtin(n.into_iter().map(f).collect()),
704-
ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData {
705-
vtable_base: o.vtable_base,
706-
nested: o.nested.into_iter().map(f).collect(),
707-
}),
708-
ImplSource::TraitUpcasting(d) => {
709-
ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
710-
vtable_vptr_slot: d.vtable_vptr_slot,
711-
nested: d.nested.into_iter().map(f).collect(),
712-
})
690+
ImplSource::Param(ct, n) => ImplSource::Param(ct, n.into_iter().map(f).collect()),
691+
ImplSource::Builtin(source, n) => {
692+
ImplSource::Builtin(source, n.into_iter().map(f).collect())
713693
}
714694
}
715695
}
@@ -733,29 +713,31 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
733713
pub nested: Vec<N>,
734714
}
735715

736-
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
737-
#[derive(TypeFoldable, TypeVisitable)]
738-
pub struct ImplSourceTraitUpcastingData<N> {
716+
#[derive(Copy, Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Debug)]
717+
pub enum BuiltinImplSource {
718+
/// Some builtin impl we don't need to differentiate. This should be used
719+
/// unless more specific information is necessary.
720+
Misc,
721+
/// A builtin impl for trait objects.
722+
///
723+
/// The vtable is formed by concatenating together the method lists of
724+
/// the base object trait and all supertraits, pointers to supertrait vtable will
725+
/// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
726+
/// in that vtable.
727+
Object { vtable_base: usize },
739728
/// The vtable is formed by concatenating together the method lists of
740729
/// the base object trait and all supertraits, pointers to supertrait vtable will
741730
/// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
742731
/// within that vtable.
743-
pub vtable_vptr_slot: Option<usize>,
744-
745-
pub nested: Vec<N>,
732+
TraitUpcasting { vtable_vptr_slot: Option<usize> },
733+
/// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
734+
///
735+
/// This needs to be a separate variant as it is still unstable and we need to emit
736+
/// a feature error when using it on stable.
737+
TupleUnsizing,
746738
}
747739

748-
#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)]
749-
#[derive(TypeFoldable, TypeVisitable)]
750-
pub struct ImplSourceObjectData<N> {
751-
/// The vtable is formed by concatenating together the method lists of
752-
/// the base object trait and all supertraits, pointers to supertrait vtable will
753-
/// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
754-
/// in that vtable.
755-
pub vtable_base: usize,
756-
757-
pub nested: Vec<N>,
758-
}
740+
TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource }
759741

760742
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
761743
pub enum ObjectSafetyViolation {

compiler/rustc_middle/src/traits/select.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,7 @@ impl From<ErrorGuaranteed> for OverflowError {
304304
}
305305
}
306306

307-
TrivialTypeTraversalAndLiftImpls! {
308-
OverflowError,
309-
}
307+
TrivialTypeTraversalAndLiftImpls! { OverflowError }
310308

311309
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
312310
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {

compiler/rustc_middle/src/traits/solve/inspect.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,12 @@ pub struct GoalCandidate<'tcx> {
7373
pub enum CandidateKind<'tcx> {
7474
/// Probe entered when normalizing the self ty during candidate assembly
7575
NormalizedSelfTyAssembly,
76+
DynUpcastingAssembly,
7677
/// A normal candidate for proving a goal
77-
Candidate { name: String, result: QueryResult<'tcx> },
78+
Candidate {
79+
name: String,
80+
result: QueryResult<'tcx>,
81+
},
7882
}
7983
impl Debug for GoalCandidate<'_> {
8084
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

compiler/rustc_middle/src/traits/solve/inspect/format.rs

+3
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
100100
CandidateKind::NormalizedSelfTyAssembly => {
101101
writeln!(self.f, "NORMALIZING SELF TY FOR ASSEMBLY:")
102102
}
103+
CandidateKind::DynUpcastingAssembly => {
104+
writeln!(self.f, "ASSEMBLING CANDIDATES FOR DYN UPCASTING:")
105+
}
103106
CandidateKind::Candidate { name, result } => {
104107
writeln!(self.f, "CANDIDATE {}: {:?}", name, result)
105108
}

compiler/rustc_middle/src/traits/structural_impls.rs

+6-28
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,16 @@ use std::fmt;
66

77
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
88
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
9-
match *self {
10-
super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v),
9+
match self {
10+
super::ImplSource::UserDefined(v) => write!(f, "{:?}", v),
1111

12-
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
13-
14-
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
12+
super::ImplSource::Builtin(source, d) => {
13+
write!(f, "Builtin({source:?}, {d:?})")
14+
}
1515

16-
super::ImplSource::Param(ref n, ct) => {
16+
super::ImplSource::Param(ct, n) => {
1717
write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
1818
}
19-
20-
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
2119
}
2220
}
2321
}
@@ -31,23 +29,3 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceUserDefinedData<'tcx,
3129
)
3230
}
3331
}
34-
35-
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<N> {
36-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37-
write!(
38-
f,
39-
"ImplSourceTraitUpcastingData(vtable_vptr_slot={:?}, nested={:?})",
40-
self.vtable_vptr_slot, self.nested
41-
)
42-
}
43-
}
44-
45-
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<N> {
46-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47-
write!(
48-
f,
49-
"ImplSourceObjectData(vtable_base={}, nested={:?})",
50-
self.vtable_base, self.nested
51-
)
52-
}
53-
}

0 commit comments

Comments
 (0)