1
Fork 0

Make everything builtin!

This commit is contained in:
Michael Goulet 2023-07-24 22:02:52 +00:00
parent de81007d13
commit a7ed9c1da7
23 changed files with 345 additions and 444 deletions

View file

@ -8,6 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt}; use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_middle::ty::{GenericArgKind, GenericArgs};
use rustc_middle::ty::{TraitRef, TypeVisitableExt}; use rustc_middle::ty::{TraitRef, TypeVisitableExt};
@ -766,7 +767,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}; };
match implsrc { match implsrc {
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => { Ok(Some(ImplSource::Param(ty::BoundConstness::ConstIfConst, _))) => {
debug!( debug!(
"const_trait_impl: provided {:?} via where-clause in {:?}", "const_trait_impl: provided {:?} via where-clause in {:?}",
trait_ref, param_env trait_ref, param_env
@ -774,7 +775,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return; return;
} }
// Closure: Fn{Once|Mut} // Closure: Fn{Once|Mut}
Ok(Some(ImplSource::Builtin(_))) Ok(Some(ImplSource::Builtin(BuiltinImplSource::Misc, _)))
if trait_ref.self_ty().is_closure() if trait_ref.self_ty().is_closure()
&& tcx.fn_trait_kind_from_def_id(trait_id).is_some() => && tcx.fn_trait_kind_from_def_id(trait_id).is_some() =>
{ {

View file

@ -7,6 +7,7 @@ use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty}; use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
@ -172,7 +173,8 @@ impl Qualif for NeedsNonConstDrop {
if !matches!( if !matches!(
impl_src, impl_src,
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst) ImplSource::Builtin(BuiltinImplSource::Misc, _)
| ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
) { ) {
// If our const destruct candidate is not ConstDestruct or implied by the param env, // If our const destruct candidate is not ConstDestruct or implied by the param env,
// then it's bad // then it's bad

View file

@ -46,6 +46,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
use rustc_infer::traits::{Obligation, PredicateObligation}; use rustc_infer::traits::{Obligation, PredicateObligation};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::adjustment::{ use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
}; };
@ -687,12 +688,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
} }
Ok(Some(impl_source)) => { Ok(Some(impl_source)) => {
// Some builtin coercions are still unstable so we detect
// these here and emit a feature error if coercion doesn't fail
// due to another reason.
match impl_source { match impl_source {
traits::ImplSource::TraitUpcasting(..) => { traits::ImplSource::Builtin(
BuiltinImplSource::TraitUpcasting { .. },
_,
) => {
has_trait_upcasting_coercion = has_trait_upcasting_coercion =
Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1))); Some((trait_pred.self_ty(), trait_pred.trait_ref.args.type_at(1)));
} }
traits::ImplSource::TupleUnsizing(_) => { traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
has_unsized_tuple_coercion = true; has_unsized_tuple_coercion = true;
} }
_ => {} _ => {}

View file

@ -43,7 +43,7 @@ macro_rules! span_bug {
#[macro_export] #[macro_export]
macro_rules! CloneLiftImpls { macro_rules! CloneLiftImpls {
($($ty:ty,)+) => { ($($ty:ty),+ $(,)?) => {
$( $(
impl<'tcx> $crate::ty::Lift<'tcx> for $ty { impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
type Lifted = Self; type Lifted = Self;
@ -59,7 +59,7 @@ macro_rules! CloneLiftImpls {
/// allocated data** (i.e., don't need to be folded). /// allocated data** (i.e., don't need to be folded).
#[macro_export] #[macro_export]
macro_rules! TrivialTypeTraversalImpls { macro_rules! TrivialTypeTraversalImpls {
($($ty:ty,)+) => { ($($ty:ty),+ $(,)?) => {
$( $(
impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty { impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty {
fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<'tcx>>>( fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<'tcx>>>(

View file

@ -178,9 +178,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
} }
} }
TrivialTypeTraversalAndLiftImpls! { TrivialTypeTraversalAndLiftImpls! { Cache }
Cache,
}
impl<S: Encoder> Encodable<S> for Cache { impl<S: Encoder> Encodable<S> for Cache {
#[inline] #[inline]

View file

@ -66,9 +66,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
} }
} }
TrivialTypeTraversalAndLiftImpls! { TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
ErrorHandled,
}
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;

View file

@ -706,9 +706,7 @@ pub enum BindingForm<'tcx> {
RefForGuard, RefForGuard,
} }
TrivialTypeTraversalAndLiftImpls! { TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
BindingForm<'tcx>,
}
mod binding_form_impl { mod binding_form_impl {
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};

View file

@ -649,46 +649,31 @@ pub enum ImplSource<'tcx, N> {
/// for some type parameter. The `Vec<N>` represents the /// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if /// obligations incurred from normalizing the where-clause (if
/// any). /// any).
Param(Vec<N>, ty::BoundConstness), Param(ty::BoundConstness, Vec<N>),
/// Virtual calls through an object. /// Successful resolution for a builtin impl.
Object(ImplSourceObjectData<N>), Builtin(BuiltinImplSource, Vec<N>),
/// Successful resolution for a builtin trait.
Builtin(Vec<N>),
// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`
TupleUnsizing(Vec<N>),
/// ImplSource for trait upcasting coercion
TraitUpcasting(ImplSourceTraitUpcastingData<N>),
} }
impl<'tcx, N> ImplSource<'tcx, N> { impl<'tcx, N> ImplSource<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> { pub fn nested_obligations(self) -> Vec<N> {
match self { match self {
ImplSource::UserDefined(i) => i.nested, ImplSource::UserDefined(i) => i.nested,
ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => n, ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n,
ImplSource::Object(d) => d.nested,
ImplSource::TraitUpcasting(d) => d.nested,
} }
} }
pub fn borrow_nested_obligations(&self) -> &[N] { pub fn borrow_nested_obligations(&self) -> &[N] {
match self { match self {
ImplSource::UserDefined(i) => &i.nested, ImplSource::UserDefined(i) => &i.nested,
ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => &n, ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => &n,
ImplSource::Object(d) => &d.nested,
ImplSource::TraitUpcasting(d) => &d.nested,
} }
} }
pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
match self { match self {
ImplSource::UserDefined(i) => &mut i.nested, ImplSource::UserDefined(i) => &mut i.nested,
ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => n, ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n,
ImplSource::Object(d) => &mut d.nested,
ImplSource::TraitUpcasting(d) => &mut d.nested,
} }
} }
@ -702,20 +687,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
args: i.args, args: i.args,
nested: i.nested.into_iter().map(f).collect(), nested: i.nested.into_iter().map(f).collect(),
}), }),
ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct), ImplSource::Param(ct, n) => ImplSource::Param(ct, n.into_iter().map(f).collect()),
ImplSource::Builtin(n) => ImplSource::Builtin(n.into_iter().map(f).collect()), ImplSource::Builtin(source, n) => {
ImplSource::TupleUnsizing(n) => { ImplSource::Builtin(source, n.into_iter().map(f).collect())
ImplSource::TupleUnsizing(n.into_iter().map(f).collect())
}
ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData {
vtable_base: o.vtable_base,
nested: o.nested.into_iter().map(f).collect(),
}),
ImplSource::TraitUpcasting(d) => {
ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
vtable_vptr_slot: d.vtable_vptr_slot,
nested: d.nested.into_iter().map(f).collect(),
})
} }
} }
} }
@ -739,30 +713,32 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
pub nested: Vec<N>, pub nested: Vec<N>,
} }
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] #[derive(Copy, Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Debug)]
#[derive(TypeFoldable, TypeVisitable)] pub enum BuiltinImplSource {
pub struct ImplSourceTraitUpcastingData<N> { /// Some builtin impl we don't need to differentiate. This should be used
/// The vtable is formed by concatenating together the method lists of /// unless more specific information is necessary.
/// the base object trait and all supertraits, pointers to supertrait vtable will Misc,
/// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable /// A builtin impl for trait objects.
/// within that vtable. ///
pub vtable_vptr_slot: Option<usize>,
pub nested: Vec<N>,
}
#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceObjectData<N> {
/// The vtable is formed by concatenating together the method lists of /// The vtable is formed by concatenating together the method lists of
/// the base object trait and all supertraits, pointers to supertrait vtable will /// the base object trait and all supertraits, pointers to supertrait vtable will
/// be provided when necessary; this is the start of `upcast_trait_ref`'s methods /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
/// in that vtable. /// in that vtable.
pub vtable_base: usize, Object { vtable_base: usize },
/// The vtable is formed by concatenating together the method lists of
pub nested: Vec<N>, /// the base object trait and all supertraits, pointers to supertrait vtable will
/// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
/// within that vtable.
TraitUpcasting { vtable_vptr_slot: Option<usize> },
/// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
///
/// This needs to be a separate variant as it is still unstable and we need to emit
/// a feature error when using it on stable.
TupleUnsizing,
} }
TrivialTypeTraversalAndLiftImpls! { BuiltinImplSource }
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
pub enum ObjectSafetyViolation { pub enum ObjectSafetyViolation {
/// `Self: Sized` declared on the trait. /// `Self: Sized` declared on the trait.

View file

@ -304,9 +304,7 @@ impl From<ErrorGuaranteed> for OverflowError {
} }
} }
TrivialTypeTraversalAndLiftImpls! { TrivialTypeTraversalAndLiftImpls! { OverflowError }
OverflowError,
}
impl<'tcx> From<OverflowError> for SelectionError<'tcx> { impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> { fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {

View file

@ -6,20 +6,16 @@ use std::fmt;
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match self {
super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v), super::ImplSource::UserDefined(v) => write!(f, "{:?}", v),
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), super::ImplSource::Builtin(source, d) => {
write!(f, "Builtin({source:?}, {d:?})")
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
super::ImplSource::Param(ref n, ct) => {
write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
} }
super::ImplSource::TupleUnsizing(ref d) => write!(f, "{:?}", d), super::ImplSource::Param(ct, n) => {
write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d), }
} }
} }
} }
@ -33,23 +29,3 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceUserDefinedData<'tcx,
) )
} }
} }
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ImplSourceTraitUpcastingData(vtable_vptr_slot={:?}, nested={:?})",
self.vtable_vptr_slot, self.nested
)
}
}
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceObjectData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"ImplSourceObjectData(vtable_base={}, nested={:?})",
self.vtable_base, self.nested
)
}
}

View file

@ -27,9 +27,7 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
} }
} }
TrivialTypeTraversalAndLiftImpls! { TrivialTypeTraversalAndLiftImpls! { NotConstEvaluatable }
NotConstEvaluatable,
}
pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>; pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;

View file

@ -6,7 +6,7 @@ pub enum BindingMode {
BindByValue(Mutability), BindByValue(Mutability),
} }
TrivialTypeTraversalAndLiftImpls! { BindingMode, } TrivialTypeTraversalAndLiftImpls! { BindingMode }
impl BindingMode { impl BindingMode {
pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode { pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {

View file

@ -3,17 +3,16 @@
use super::search_graph::OverflowHandler; use super::search_graph::OverflowHandler;
use super::{EvalCtxt, SolverMode}; use super::{EvalCtxt, SolverMode};
use crate::traits::coherence; use crate::traits::coherence;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::elaborate;
use rustc_infer::traits::Reveal; use rustc_infer::traits::Reveal;
use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::inspect::CandidateKind;
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult}; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams}; use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{fast_reject, TypeFoldable}; use rustc_middle::ty::{fast_reject, TypeFoldable};
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
use rustc_span::ErrorGuaranteed; use rustc_span::ErrorGuaranteed;
use std::fmt::Debug; use std::fmt::Debug;
@ -89,17 +88,6 @@ pub(super) enum CandidateSource {
AliasBound, AliasBound,
} }
/// Records additional information about what kind of built-in impl this is.
/// This should only be used by selection.
#[derive(Debug, Clone, Copy)]
pub(super) enum BuiltinImplSource {
TraitUpcasting,
TupleUnsize,
Object,
Misc,
Ambiguity,
}
/// Methods used to assemble candidates for either trait or projection goals. /// Methods used to assemble candidates for either trait or projection goals.
pub(super) trait GoalKind<'tcx>: pub(super) trait GoalKind<'tcx>:
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
@ -282,20 +270,6 @@ pub(super) trait GoalKind<'tcx>:
goal: Goal<'tcx, Self>, goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>; ) -> QueryResult<'tcx>;
/// Consider (possibly several) goals to upcast or unsize a type to another
/// type.
///
/// The most common forms of unsizing are array to slice, and concrete (Sized)
/// type into a `dyn Trait`. ADTs and Tuples can also have their final field
/// unsized if it's generic.
///
/// `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or
/// if `Trait2` is a (transitive) supertrait of `Trait2`.
fn consider_builtin_unsize_and_upcast_candidates(
_ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>;
fn consider_builtin_discriminant_kind_candidate( fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>, ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>, goal: Goal<'tcx, Self>,
@ -310,6 +284,25 @@ pub(super) trait GoalKind<'tcx>:
ecx: &mut EvalCtxt<'_, 'tcx>, ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>, goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>; ) -> QueryResult<'tcx>;
/// Consider (possibly several) candidates to upcast or unsize a type to another
/// type.
///
/// The most common forms of unsizing are array to slice, and concrete (Sized)
/// type into a `dyn Trait`. ADTs and Tuples can also have their final field
/// unsized if it's generic.
///
/// `dyn Trait1` can be unsized to `dyn Trait2` if they are the same trait, or
/// if `Trait2` is a (transitive) supertrait of `Trait2`.
///
/// We return the `BuiltinImplSource` for each candidate as it is needed
/// for unsize coercion in hir typeck and because it is difficult to
/// otherwise recompute this for codegen. This is a bit of a mess but the
/// easiest way to maintain the existing behavior for now.
fn consider_builtin_unsize_and_upcast_candidates(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)>;
} }
impl<'tcx> EvalCtxt<'_, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> {
@ -343,7 +336,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
) -> Option<Vec<Candidate<'tcx>>> { ) -> Option<Vec<Candidate<'tcx>>> {
goal.predicate.self_ty().is_ty_var().then(|| { goal.predicate.self_ty().is_ty_var().then(|| {
vec![Candidate { vec![Candidate {
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity), source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
result: self result: self
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
.unwrap(), .unwrap(),
@ -412,7 +405,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
Certainty::Maybe(MaybeCause::Overflow), Certainty::Maybe(MaybeCause::Overflow),
)?; )?;
Ok(vec![Candidate { Ok(vec![Candidate {
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity), source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
result, result,
}]) }])
}, },
@ -848,29 +841,47 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
ty::Dynamic(bounds, ..) => bounds, ty::Dynamic(bounds, ..) => bounds,
}; };
let own_bounds: FxIndexSet<_> = // Consider all of the auto-trait and projection bounds, which don't
bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect(); // need to be recorded as a `BuiltinImplSource::Object` since they don't
for assumption in elaborate(tcx, own_bounds.iter().copied()) // really have a vtable base...
// we only care about bounds that match the `Self` type for bound in bounds {
.filter_only_self() match bound.skip_binder() {
{ ty::ExistentialPredicate::Trait(_) => {
// FIXME: Predicates are fully elaborated in the object type's existential bounds // Skip principal
// list. We want to only consider these pre-elaborated projections, and not other }
// projection predicates that we reach by elaborating the principal trait ref, ty::ExistentialPredicate::Projection(_)
// since that'll cause ambiguity. | ty::ExistentialPredicate::AutoTrait(_) => {
// match G::consider_object_bound_candidate(
// We can remove this when we have implemented lifetime intersections in responses. self,
if assumption.as_projection_clause().is_some() && !own_bounds.contains(&assumption) { goal,
continue; bound.with_self_ty(tcx, self_ty),
) {
Ok(result) => candidates.push(Candidate {
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
result,
}),
Err(NoSolution) => (),
}
}
} }
}
match G::consider_object_bound_candidate(self, goal, assumption) { // FIXME: We only need to do *any* of this if we're considering a trait goal,
Ok(result) => candidates.push(Candidate { // since we don't need to look at any supertrait or anything if we are doing
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object), // a projection goal.
result, if let Some(principal) = bounds.principal() {
}), let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
Err(NoSolution) => (), self.walk_vtable(principal_trait_ref, |ecx, assumption, vtable_base, _| {
} match G::consider_object_bound_candidate(ecx, goal, assumption.to_predicate(tcx)) {
Ok(result) => candidates.push(Candidate {
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object {
vtable_base,
}),
result,
}),
Err(NoSolution) => (),
}
});
} }
} }
@ -890,7 +901,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
{ {
Ok(result) => candidates.push(Candidate { Ok(result) => candidates.push(Candidate {
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity), source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
result, result,
}), }),
// FIXME: This will be reachable at some point if we're in // FIXME: This will be reachable at some point if we're in

View file

@ -25,6 +25,7 @@ use std::io::Write;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use crate::traits::specialization_graph; use crate::traits::specialization_graph;
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
use super::inspect::ProofTreeBuilder; use super::inspect::ProofTreeBuilder;
use super::search_graph::{self, OverflowHandler}; use super::search_graph::{self, OverflowHandler};
@ -920,4 +921,39 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
Err(ErrorHandled::TooGeneric) => None, Err(ErrorHandled::TooGeneric) => None,
} }
} }
/// Walk through the vtable of a principal trait ref, executing a `supertrait_visitor`
/// for every trait ref encountered (including the principal). Passes both the vtable
/// base and the (optional) vptr slot.
pub(super) fn walk_vtable(
&mut self,
principal: ty::PolyTraitRef<'tcx>,
mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option<usize>),
) {
let tcx = self.tcx();
let mut offset = 0;
prepare_vtable_segments::<()>(tcx, principal, |segment| {
match segment {
VtblSegment::MetadataDSA => {
offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
}
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
let own_vtable_entries = count_own_vtable_entries(tcx, trait_ref);
supertrait_visitor(
self,
trait_ref,
offset,
emit_vptr.then(|| offset + own_vtable_entries),
);
offset += own_vtable_entries;
if emit_vptr {
offset += 1;
}
}
}
ControlFlow::Continue(())
});
}
} }

View file

@ -1,25 +1,20 @@
use std::ops::ControlFlow;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt};
use rustc_infer::traits::util::supertraits;
use rustc_infer::traits::{ use rustc_infer::traits::{
Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine, Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine,
}; };
use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal}; use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
use rustc_middle::traits::{ use rustc_middle::traits::{
ImplSource, ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, ObligationCause, SelectionError,
ObligationCause, SelectionError,
}; };
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use crate::solve::assembly::{BuiltinImplSource, Candidate, CandidateSource}; use crate::solve::assembly::{Candidate, CandidateSource};
use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree}; use crate::solve::eval_ctxt::{EvalCtxt, GenerateProofTree};
use crate::solve::inspect::ProofTreeBuilder; use crate::solve::inspect::ProofTreeBuilder;
use crate::solve::search_graph::OverflowHandler; use crate::solve::search_graph::OverflowHandler;
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
use crate::traits::StructurallyNormalizeExt; use crate::traits::StructurallyNormalizeExt;
use crate::traits::TraitEngineExt; use crate::traits::TraitEngineExt;
@ -105,47 +100,26 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
rematch_impl(self, goal, def_id, nested_obligations) rematch_impl(self, goal, def_id, nested_obligations)
} }
// Rematching the dyn upcast or object goal will instantiate the same nested (Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
// goals that would have caused the ambiguity, so we can still make progress here
// regardless.
// FIXME: This doesn't actually check the object bounds hold here.
(
_,
CandidateSource::BuiltinImpl(
BuiltinImplSource::Object | BuiltinImplSource::TraitUpcasting,
),
) => rematch_object(self, goal, nested_obligations),
(
Certainty::Maybe(_),
CandidateSource::BuiltinImpl(
BuiltinImplSource::Misc | BuiltinImplSource::TupleUnsize,
),
) if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) => {
rematch_unsize(self, goal, nested_obligations)
}
(Certainty::Yes, CandidateSource::BuiltinImpl(BuiltinImplSource::TupleUnsize))
if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) => if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
{ {
Ok(Some(ImplSource::TupleUnsizing(nested_obligations))) rematch_unsize(self, goal, nested_obligations, src)
} }
// Technically some builtin impls have nested obligations, but if // Technically some builtin impls have nested obligations, but if
// `Certainty::Yes`, then they should've all been verified and don't // `Certainty::Yes`, then they should've all been verified and don't
// need re-checking. // need re-checking.
(Certainty::Yes, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc)) => { (Certainty::Yes, CandidateSource::BuiltinImpl(src)) => {
Ok(Some(ImplSource::Builtin(nested_obligations))) Ok(Some(ImplSource::Builtin(src, nested_obligations)))
} }
// It's fine not to do anything to rematch these, since there are no // It's fine not to do anything to rematch these, since there are no
// nested obligations. // nested obligations.
(Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => { (Certainty::Yes, CandidateSource::ParamEnv(_) | CandidateSource::AliasBound) => {
Ok(Some(ImplSource::Param(nested_obligations, ty::BoundConstness::NotConst))) Ok(Some(ImplSource::Param(ty::BoundConstness::NotConst, nested_obligations)))
} }
(_, CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity)) (Certainty::Maybe(_), _) => Ok(None),
| (Certainty::Maybe(_), _) => Ok(None),
} }
} }
} }
@ -192,11 +166,12 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>(
} }
(_, CandidateSource::ParamEnv(_)) => true, (_, CandidateSource::ParamEnv(_)) => true,
// FIXME: we could prefer earlier vtable bases perhaps...
( (
CandidateSource::BuiltinImpl(BuiltinImplSource::Object), CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
CandidateSource::BuiltinImpl(BuiltinImplSource::Object), CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }),
) => false, ) => false,
(_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object)) => true, (_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. })) => true,
(CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => { (CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_def_id)) => {
tcx.specializes((other_def_id, victim_def_id)) tcx.specializes((other_def_id, victim_def_id))
@ -234,108 +209,6 @@ fn rematch_impl<'tcx>(
Ok(Some(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, args, nested }))) Ok(Some(ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id, args, nested })))
} }
fn rematch_object<'tcx>(
infcx: &InferCtxt<'tcx>,
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
mut nested: Vec<PredicateObligation<'tcx>>,
) -> SelectionResult<'tcx, Selection<'tcx>> {
let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
let ty::Dynamic(data, _, source_kind) = *a_ty.kind() else { bug!() };
let source_trait_ref = data.principal().unwrap().with_self_ty(infcx.tcx, a_ty);
let (is_upcasting, target_trait_ref_unnormalized) =
if Some(goal.predicate.def_id()) == infcx.tcx.lang_items().unsize_trait() {
assert_eq!(source_kind, ty::Dyn, "cannot upcast dyn*");
let b_ty = structurally_normalize(
goal.predicate.trait_ref.args.type_at(1),
infcx,
goal.param_env,
&mut nested,
);
if let ty::Dynamic(data, _, ty::Dyn) = *b_ty.kind() {
// FIXME: We also need to ensure that the source lifetime outlives the
// target lifetime. This doesn't matter for codegen, though, and only
// *really* matters if the goal's certainty is ambiguous.
(true, data.principal().unwrap().with_self_ty(infcx.tcx, a_ty))
} else {
bug!()
}
} else {
(false, ty::Binder::dummy(goal.predicate.trait_ref))
};
let mut target_trait_ref = None;
for candidate_trait_ref in supertraits(infcx.tcx, source_trait_ref) {
let result = infcx.commit_if_ok(|_| {
infcx.at(&ObligationCause::dummy(), goal.param_env).eq(
DefineOpaqueTypes::No,
target_trait_ref_unnormalized,
candidate_trait_ref,
)
// FIXME: We probably should at least shallowly verify these...
});
match result {
Ok(InferOk { value: (), obligations }) => {
target_trait_ref = Some(candidate_trait_ref);
nested.extend(obligations);
break;
}
Err(_) => continue,
}
}
let target_trait_ref = target_trait_ref.unwrap();
let mut offset = 0;
let Some((vtable_base, vtable_vptr_slot)) =
prepare_vtable_segments(infcx.tcx, source_trait_ref, |segment| {
match segment {
VtblSegment::MetadataDSA => {
offset += TyCtxt::COMMON_VTABLE_ENTRIES.len();
}
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
let own_vtable_entries = count_own_vtable_entries(infcx.tcx, trait_ref);
if trait_ref == target_trait_ref {
if emit_vptr {
return ControlFlow::Break((
offset,
Some(offset + count_own_vtable_entries(infcx.tcx, trait_ref)),
));
} else {
return ControlFlow::Break((offset, None));
}
}
offset += own_vtable_entries;
if emit_vptr {
offset += 1;
}
}
}
ControlFlow::Continue(())
})
else {
bug!();
};
// If we're upcasting, get the offset of the vtable pointer, otherwise get
// the base of the vtable.
Ok(Some(if is_upcasting {
// If source and target trait def ids are identical,
// then we are simply removing auto traits.
if source_trait_ref.def_id() == target_trait_ref.def_id() {
ImplSource::Builtin(nested)
} else {
ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested })
}
} else {
ImplSource::Object(ImplSourceObjectData { vtable_base, nested })
}))
}
/// The `Unsize` trait is particularly important to coercion, so we try rematch it. /// The `Unsize` trait is particularly important to coercion, so we try rematch it.
/// NOTE: This must stay in sync with `consider_builtin_unsize_candidate` in trait /// NOTE: This must stay in sync with `consider_builtin_unsize_candidate` in trait
/// goal assembly in the solver, both for soundness and in order to avoid ICEs. /// goal assembly in the solver, both for soundness and in order to avoid ICEs.
@ -343,6 +216,7 @@ fn rematch_unsize<'tcx>(
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>, goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
mut nested: Vec<PredicateObligation<'tcx>>, mut nested: Vec<PredicateObligation<'tcx>>,
source: BuiltinImplSource,
) -> SelectionResult<'tcx, Selection<'tcx>> { ) -> SelectionResult<'tcx, Selection<'tcx>> {
let tcx = infcx.tcx; let tcx = infcx.tcx;
let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested); let a_ty = structurally_normalize(goal.predicate.self_ty(), infcx, goal.param_env, &mut nested);
@ -379,6 +253,8 @@ fn rematch_unsize<'tcx>(
goal.param_env, goal.param_env,
ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)), ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)),
)); ));
Ok(Some(ImplSource::Builtin(source, nested)))
} }
// `[T; n]` -> `[T]` unsizing // `[T; n]` -> `[T]` unsizing
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { (&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
@ -389,6 +265,8 @@ fn rematch_unsize<'tcx>(
.expect("expected rematch to succeed") .expect("expected rematch to succeed")
.into_obligations(), .into_obligations(),
); );
Ok(Some(ImplSource::Builtin(source, nested)))
} }
// Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>` // Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
@ -439,6 +317,8 @@ fn rematch_unsize<'tcx>(
goal.param_env, goal.param_env,
ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]), ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
)); ));
Ok(Some(ImplSource::Builtin(source, nested)))
} }
// Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>` // Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
(&ty::Tuple(a_tys), &ty::Tuple(b_tys)) (&ty::Tuple(a_tys), &ty::Tuple(b_tys))
@ -467,15 +347,18 @@ fn rematch_unsize<'tcx>(
)); ));
// We need to be able to detect tuple unsizing to require its feature gate. // We need to be able to detect tuple unsizing to require its feature gate.
return Ok(Some(ImplSource::TupleUnsizing(nested))); assert_eq!(
source,
BuiltinImplSource::TupleUnsizing,
"compiler-errors wants to know if this can ever be triggered..."
);
Ok(Some(ImplSource::Builtin(source, nested)))
} }
// FIXME: We *could* ICE here if either: // FIXME: We *could* ICE here if either:
// 1. the certainty is `Certainty::Yes`, // 1. the certainty is `Certainty::Yes`,
// 2. we're in codegen (which should mean `Certainty::Yes`). // 2. we're in codegen (which should mean `Certainty::Yes`).
_ => return Ok(None), _ => Ok(None),
} }
Ok(Some(ImplSource::Builtin(nested)))
} }
fn structurally_normalize<'tcx>( fn structurally_normalize<'tcx>(

View file

@ -1,6 +1,6 @@
use crate::traits::specialization_graph; use crate::traits::specialization_graph;
use super::assembly::{self, structural_traits, BuiltinImplSource}; use super::assembly::{self, structural_traits};
use super::EvalCtxt; use super::EvalCtxt;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -10,6 +10,7 @@ use rustc_infer::traits::specialization_graph::LeafDef;
use rustc_infer::traits::Reveal; use rustc_infer::traits::Reveal;
use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::inspect::CandidateKind;
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::ProjectionPredicate; use rustc_middle::ty::ProjectionPredicate;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};

View file

@ -1,15 +1,14 @@
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`. //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
use super::assembly::{self, structural_traits, BuiltinImplSource}; use super::assembly::{self, structural_traits};
use super::search_graph::OverflowHandler; use super::search_graph::OverflowHandler;
use super::{EvalCtxt, SolverMode}; use super::{EvalCtxt, SolverMode};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{LangItem, Movability}; use rustc_hir::{LangItem, Movability};
use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::supertraits;
use rustc_middle::traits::solve::inspect::CandidateKind; use rustc_middle::traits::solve::inspect::CandidateKind;
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult}; use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
use rustc_middle::traits::Reveal; use rustc_middle::traits::{BuiltinImplSource, Reveal};
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
@ -382,37 +381,48 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let b_ty = match ecx let b_ty = match ecx
.normalize_non_self_ty(goal.predicate.trait_ref.args.type_at(1), goal.param_env) .normalize_non_self_ty(goal.predicate.trait_ref.args.type_at(1), goal.param_env)
{ {
Ok(Some(b_ty)) if !b_ty.is_ty_var() => b_ty, Ok(Some(b_ty)) => {
Ok(_) => { // If we have a type var, then bail with ambiguity.
return vec![( if b_ty.is_ty_var() {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) return vec![(
ecx.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
)
.unwrap(), .unwrap(),
BuiltinImplSource::Ambiguity, BuiltinImplSource::Misc,
)];
} else {
b_ty
}
}
Ok(None) => {
return vec![(
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe(
MaybeCause::Overflow,
))
.unwrap(),
BuiltinImplSource::Misc,
)]; )];
} }
Err(_) => return vec![], Err(_) => return vec![],
}; };
let mut results = vec![]; let mut results = vec![];
results.extend(ecx.consider_builtin_dyn_upcast_candidates(goal.param_env, a_ty, b_ty));
results.extend( results.extend(
ecx.consider_builtin_dyn_upcast_candidates(goal.param_env, a_ty, b_ty) ecx.consider_builtin_unsize_candidate(goal.with(ecx.tcx(), (a_ty, b_ty)))
.into_iter() .into_iter()
.map(|resp| (resp, BuiltinImplSource::TraitUpcasting)), .map(|resp| {
);
results.extend(
ecx.consider_builtin_unsize_candidate(goal.param_env, a_ty, b_ty).into_iter().map(
|resp| {
// If we're unsizing from tuple -> tuple, detect // If we're unsizing from tuple -> tuple, detect
let source = let source =
if matches!((a_ty.kind(), b_ty.kind()), (ty::Tuple(..), ty::Tuple(..))) if matches!((a_ty.kind(), b_ty.kind()), (ty::Tuple(..), ty::Tuple(..)))
{ {
BuiltinImplSource::TupleUnsize BuiltinImplSource::TupleUnsizing
} else { } else {
BuiltinImplSource::Misc BuiltinImplSource::Misc
}; };
(resp, source) (resp, source)
}, }),
),
); );
results results
@ -484,10 +494,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
impl<'tcx> EvalCtxt<'_, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> {
fn consider_builtin_unsize_candidate( fn consider_builtin_unsize_candidate(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>,
) -> QueryResult<'tcx> { ) -> QueryResult<'tcx> {
let Goal { param_env, predicate: (a_ty, b_ty) } = goal;
self.probe_candidate("builtin unsize").enter(|ecx| { self.probe_candidate("builtin unsize").enter(|ecx| {
let tcx = ecx.tcx(); let tcx = ecx.tcx();
match (a_ty.kind(), b_ty.kind()) { match (a_ty.kind(), b_ty.kind()) {
@ -614,7 +623,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
a_ty: Ty<'tcx>, a_ty: Ty<'tcx>,
b_ty: Ty<'tcx>, b_ty: Ty<'tcx>,
) -> Vec<CanonicalResponse<'tcx>> { ) -> Vec<(CanonicalResponse<'tcx>, BuiltinImplSource)> {
if a_ty.is_ty_var() || b_ty.is_ty_var() { if a_ty.is_ty_var() || b_ty.is_ty_var() {
bug!("unexpected type variable in unsize goal") bug!("unexpected type variable in unsize goal")
} }
@ -634,57 +643,64 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
return vec![]; return vec![];
} }
let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| { // Try to match `a_ty` against `b_ty`, replacing `a_ty`'s principal trait ref with
self.probe_candidate("upcast dyn to principle").enter(|ecx| -> Result<_, NoSolution> { // the supertrait principal and subtyping the types.
// Require that all of the trait predicates from A match B, except for let unsize_dyn_to_principal =
// the auto traits. We do this by constructing a new A type with B's |ecx: &mut Self, principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
// auto traits, and equating these types. ecx.probe_candidate("upcast dyn to principle").enter(
let new_a_data = principal |ecx| -> Result<_, NoSolution> {
.into_iter() // Require that all of the trait predicates from A match B, except for
.map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)) // the auto traits. We do this by constructing a new A type with B's
.chain(a_data.iter().filter(|a| { // auto traits, and equating these types.
matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_)) let new_a_data = principal
})) .into_iter()
.chain( .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait))
b_data .chain(a_data.iter().filter(|a| {
.auto_traits() matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_))
.map(ty::ExistentialPredicate::AutoTrait) }))
.map(ty::Binder::dummy), .chain(
); b_data
let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data); .auto_traits()
let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn); .map(ty::ExistentialPredicate::AutoTrait)
.map(ty::Binder::dummy),
);
let new_a_data = tcx.mk_poly_existential_predicates_from_iter(new_a_data);
let new_a_ty = Ty::new_dynamic(tcx, new_a_data, b_region, ty::Dyn);
// We also require that A's lifetime outlives B's lifetime. // We also require that A's lifetime outlives B's lifetime.
ecx.eq(param_env, new_a_ty, b_ty)?; ecx.eq(param_env, new_a_ty, b_ty)?;
ecx.add_goal(Goal::new( ecx.add_goal(Goal::new(
tcx, tcx,
param_env, param_env,
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
)); ));
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}) },
}; )
};
let mut responses = vec![]; let mut responses = vec![];
// If the principal def ids match (or are both none), then we're not doing // If the principal def ids match (or are both none), then we're not doing
// trait upcasting. We're just removing auto traits (or shortening the lifetime). // trait upcasting. We're just removing auto traits (or shortening the lifetime).
if a_data.principal_def_id() == b_data.principal_def_id() { if a_data.principal_def_id() == b_data.principal_def_id() {
if let Ok(response) = unsize_dyn_to_principal(a_data.principal()) { if let Ok(resp) = unsize_dyn_to_principal(self, a_data.principal()) {
responses.push(response); responses.push((resp, BuiltinImplSource::Misc));
}
} else if let Some(a_principal) = a_data.principal()
&& let Some(b_principal) = b_data.principal()
{
for super_trait_ref in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)) {
if super_trait_ref.def_id() != b_principal.def_id() {
continue;
}
let erased_trait_ref = super_trait_ref
.map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
if let Ok(response) = unsize_dyn_to_principal(Some(erased_trait_ref)) {
responses.push(response);
}
} }
} else if let Some(a_principal) = a_data.principal() {
self.walk_vtable(
a_principal.with_self_ty(tcx, a_ty),
|ecx, new_a_principal, _, vtable_vptr_slot| {
if let Ok(resp) = unsize_dyn_to_principal(
ecx,
Some(new_a_principal.map_bound(|trait_ref| {
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
})),
) {
responses
.push((resp, BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }));
}
},
);
} }
responses responses

View file

@ -4,7 +4,6 @@ use super::check_args_compatible;
use super::specialization_graph; use super::specialization_graph;
use super::translate_args; use super::translate_args;
use super::util; use super::util;
use super::ImplSourceUserDefinedData;
use super::MismatchedProjectionTypes; use super::MismatchedProjectionTypes;
use super::Obligation; use super::Obligation;
use super::ObligationCause; use super::ObligationCause;
@ -13,6 +12,9 @@ use super::Selection;
use super::SelectionContext; use super::SelectionContext;
use super::SelectionError; use super::SelectionError;
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::traits::ImplSource;
use rustc_middle::traits::ImplSourceUserDefinedData;
use crate::errors::InherentProjectionNormalizationOverflow; use crate::errors::InherentProjectionNormalizationOverflow;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@ -1717,7 +1719,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
}; };
let eligible = match &impl_source { let eligible = match &impl_source {
super::ImplSource::UserDefined(impl_data) => { ImplSource::UserDefined(impl_data) => {
// We have to be careful when projecting out of an // We have to be careful when projecting out of an
// impl because of specialization. If we are not in // impl because of specialization. If we are not in
// codegen (i.e., projection mode is not "any"), and the // codegen (i.e., projection mode is not "any"), and the
@ -1767,7 +1769,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
} }
} }
} }
super::ImplSource::Builtin(..) => { ImplSource::Builtin(BuiltinImplSource::Misc, _) => {
// While a builtin impl may be known to exist, the associated type may not yet // While a builtin impl may be known to exist, the associated type may not yet
// be known. Any type with multiple potential associated types is therefore // be known. Any type with multiple potential associated types is therefore
// not eligible. // not eligible.
@ -1891,7 +1893,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
bug!("unexpected builtin trait with associated type: {trait_ref:?}") bug!("unexpected builtin trait with associated type: {trait_ref:?}")
} }
} }
super::ImplSource::Param(..) => { ImplSource::Param(..) => {
// This case tell us nothing about the value of an // This case tell us nothing about the value of an
// associated type. Consider: // associated type. Consider:
// //
@ -1919,14 +1921,14 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// in `assemble_candidates_from_param_env`. // in `assemble_candidates_from_param_env`.
false false
} }
super::ImplSource::Object(_) => { ImplSource::Builtin(BuiltinImplSource::Object { .. }, _) => {
// Handled by the `Object` projection candidate. See // Handled by the `Object` projection candidate. See
// `assemble_candidates_from_object_ty` for an explanation of // `assemble_candidates_from_object_ty` for an explanation of
// why we special case object types. // why we special case object types.
false false
} }
super::ImplSource::TraitUpcasting(_) ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
| super::ImplSource::TupleUnsizing(_) => { | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
// These traits have no associated types. // These traits have no associated types.
selcx.tcx().sess.delay_span_bug( selcx.tcx().sess.delay_span_bug(
obligation.cause.span, obligation.cause.span,
@ -1986,8 +1988,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
impl_source: Selection<'tcx>, impl_source: Selection<'tcx>,
) -> Progress<'tcx> { ) -> Progress<'tcx> {
match impl_source { match impl_source {
super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
super::ImplSource::Builtin(data) => { ImplSource::Builtin(BuiltinImplSource::Misc, data) => {
let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx()); let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx());
let lang_items = selcx.tcx().lang_items(); let lang_items = selcx.tcx().lang_items();
if lang_items.gen_trait() == Some(trait_def_id) { if lang_items.gen_trait() == Some(trait_def_id) {
@ -2004,10 +2006,10 @@ fn confirm_select_candidate<'cx, 'tcx>(
confirm_builtin_candidate(selcx, obligation, data) confirm_builtin_candidate(selcx, obligation, data)
} }
} }
super::ImplSource::Object(_) ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)
| super::ImplSource::Param(..) | ImplSource::Param(..)
| super::ImplSource::TraitUpcasting(_) | ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
| super::ImplSource::TupleUnsizing(_) => { | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
// we don't create Select candidates with this kind of resolution // we don't create Select candidates with this kind of resolution
span_bug!( span_bug!(
obligation.cause.span, obligation.cause.span,

View file

@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
use rustc_middle::traits::SelectionOutputTypeParameterMismatch; use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch};
use rustc_middle::ty::{ use rustc_middle::ty::{
self, Binder, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate, self, Binder, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
TraitPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt, TraitPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt,
@ -26,9 +26,9 @@ use crate::traits::vtable::{
}; };
use crate::traits::{ use crate::traits::{
BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource, BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
Obligation, ObligationCause, OutputTypeParameterMismatch, PolyTraitObligation, OutputTypeParameterMismatch, PolyTraitObligation, PredicateObligation, Selection,
PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, Unimplemented, SelectionError, TraitNotObjectSafe, Unimplemented,
}; };
use super::BuiltinImplConditions; use super::BuiltinImplConditions;
@ -48,18 +48,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut impl_src = match candidate { let mut impl_src = match candidate {
BuiltinCandidate { has_nested } => { BuiltinCandidate { has_nested } => {
let data = self.confirm_builtin_candidate(obligation, has_nested); let data = self.confirm_builtin_candidate(obligation, has_nested);
ImplSource::Builtin(data) ImplSource::Builtin(BuiltinImplSource::Misc, data)
} }
TransmutabilityCandidate => { TransmutabilityCandidate => {
let data = self.confirm_transmutability_candidate(obligation)?; let data = self.confirm_transmutability_candidate(obligation)?;
ImplSource::Builtin(data) ImplSource::Builtin(BuiltinImplSource::Misc, data)
} }
ParamCandidate(param) => { ParamCandidate(param) => {
let obligations = let obligations =
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
ImplSource::Param(obligations, param.skip_binder().constness) ImplSource::Param(param.skip_binder().constness, obligations)
} }
ImplCandidate(impl_def_id) => { ImplCandidate(impl_def_id) => {
@ -68,76 +68,57 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
AutoImplCandidate => { AutoImplCandidate => {
let data = self.confirm_auto_impl_candidate(obligation)?; let data = self.confirm_auto_impl_candidate(obligation)?;
ImplSource::Builtin(data) ImplSource::Builtin(BuiltinImplSource::Misc, data)
} }
ProjectionCandidate(idx, constness) => { ProjectionCandidate(idx, constness) => {
let obligations = self.confirm_projection_candidate(obligation, idx)?; let obligations = self.confirm_projection_candidate(obligation, idx)?;
ImplSource::Param(obligations, constness) ImplSource::Param(constness, obligations)
} }
ObjectCandidate(idx) => { ObjectCandidate(idx) => self.confirm_object_candidate(obligation, idx)?,
let data = self.confirm_object_candidate(obligation, idx)?;
ImplSource::Object(data)
}
ClosureCandidate { .. } => { ClosureCandidate { .. } => {
let vtable_closure = self.confirm_closure_candidate(obligation)?; let vtable_closure = self.confirm_closure_candidate(obligation)?;
ImplSource::Builtin(vtable_closure) ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
} }
GeneratorCandidate => { GeneratorCandidate => {
let vtable_generator = self.confirm_generator_candidate(obligation)?; let vtable_generator = self.confirm_generator_candidate(obligation)?;
ImplSource::Builtin(vtable_generator) ImplSource::Builtin(BuiltinImplSource::Misc, vtable_generator)
} }
FutureCandidate => { FutureCandidate => {
let vtable_future = self.confirm_future_candidate(obligation)?; let vtable_future = self.confirm_future_candidate(obligation)?;
ImplSource::Builtin(vtable_future) ImplSource::Builtin(BuiltinImplSource::Misc, vtable_future)
} }
FnPointerCandidate { is_const } => { FnPointerCandidate { is_const } => {
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?; let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
ImplSource::Builtin(data) ImplSource::Builtin(BuiltinImplSource::Misc, data)
} }
TraitAliasCandidate => { TraitAliasCandidate => {
let data = self.confirm_trait_alias_candidate(obligation); let data = self.confirm_trait_alias_candidate(obligation);
ImplSource::Builtin(data) ImplSource::Builtin(BuiltinImplSource::Misc, data)
} }
BuiltinObjectCandidate => { BuiltinObjectCandidate => {
// This indicates something like `Trait + Send: Send`. In this case, we know that // This indicates something like `Trait + Send: Send`. In this case, we know that
// this holds because that's what the object type is telling us, and there's really // this holds because that's what the object type is telling us, and there's really
// no additional obligations to prove and no types in particular to unify, etc. // no additional obligations to prove and no types in particular to unify, etc.
ImplSource::Builtin(Vec::new()) ImplSource::Builtin(BuiltinImplSource::Misc, Vec::new())
} }
BuiltinUnsizeCandidate => { BuiltinUnsizeCandidate => self.confirm_builtin_unsize_candidate(obligation)?,
let source =
self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
let target = self.infcx.shallow_resolve(target);
let data = self.confirm_builtin_unsize_candidate(obligation, source, target)?;
// If the source and target are both unsize goals, then we need to signify that
// this is tuple unsizing so that during unsized coercion we require the proper
// feature gate.
if matches!(source.kind(), ty::Tuple(..)) && matches!(target.kind(), ty::Tuple(..))
{
ImplSource::TupleUnsizing(data)
} else {
ImplSource::Builtin(data)
}
}
TraitUpcastingUnsizeCandidate(idx) => { TraitUpcastingUnsizeCandidate(idx) => {
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?; self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?
ImplSource::TraitUpcasting(data)
} }
ConstDestructCandidate(def_id) => { ConstDestructCandidate(def_id) => {
let data = self.confirm_const_destruct_candidate(obligation, def_id)?; let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
ImplSource::Builtin(data) ImplSource::Builtin(BuiltinImplSource::Misc, data)
} }
}; };
@ -496,7 +477,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
index: usize, index: usize,
) -> Result<ImplSourceObjectData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx(); let tcx = self.tcx();
debug!(?obligation, ?index, "confirm_object_candidate"); debug!(?obligation, ?index, "confirm_object_candidate");
@ -660,7 +641,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
(unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)), (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
); );
Ok(ImplSourceObjectData { vtable_base, nested }) Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested))
} }
fn confirm_fn_pointer_candidate( fn confirm_fn_pointer_candidate(
@ -909,7 +890,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
idx: usize, idx: usize,
) -> Result<ImplSourceTraitUpcastingData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx(); let tcx = self.tcx();
// `assemble_candidates_for_unsizing` should ensure there are no late-bound // `assemble_candidates_for_unsizing` should ensure there are no late-bound
@ -1006,19 +987,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let vtable_vptr_slot = let vtable_vptr_slot =
prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap(); prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback).unwrap();
Ok(ImplSourceTraitUpcastingData { vtable_vptr_slot, nested }) Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, nested))
} }
fn confirm_builtin_unsize_candidate( fn confirm_builtin_unsize_candidate(
&mut self, &mut self,
obligation: &PolyTraitObligation<'tcx>, obligation: &PolyTraitObligation<'tcx>,
source: Ty<'tcx>, ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
target: Ty<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let tcx = self.tcx(); let tcx = self.tcx();
// `assemble_candidates_for_unsizing` should ensure there are no late-bound
// regions here. See the comment there for more details.
let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
let target = self.infcx.shallow_resolve(target);
debug!(?source, ?target, "confirm_builtin_unsize_candidate"); debug!(?source, ?target, "confirm_builtin_unsize_candidate");
let mut nested = vec![]; let mut nested = vec![];
let src;
match (source.kind(), target.kind()) { match (source.kind(), target.kind()) {
// Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
(&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b)) (&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b))
@ -1062,6 +1048,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.param_env, obligation.param_env,
obligation.predicate.rebind(outlives), obligation.predicate.rebind(outlives),
)); ));
src = BuiltinImplSource::Misc;
} }
// `T` -> `Trait` // `T` -> `Trait`
@ -1108,6 +1096,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.push(predicate_to_obligation( nested.push(predicate_to_obligation(
ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx), ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx),
)); ));
src = BuiltinImplSource::Misc;
} }
// `[T; n]` -> `[T]` // `[T; n]` -> `[T]`
@ -1118,6 +1108,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.eq(DefineOpaqueTypes::No, b, a) .eq(DefineOpaqueTypes::No, b, a)
.map_err(|_| Unimplemented)?; .map_err(|_| Unimplemented)?;
nested.extend(obligations); nested.extend(obligations);
src = BuiltinImplSource::Misc;
} }
// `Struct<T>` -> `Struct<U>` // `Struct<T>` -> `Struct<U>`
@ -1174,6 +1166,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
), ),
); );
nested.push(tail_unsize_obligation); nested.push(tail_unsize_obligation);
src = BuiltinImplSource::Misc;
} }
// `(.., T)` -> `(.., U)` // `(.., T)` -> `(.., U)`
@ -1201,12 +1195,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]), ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]),
); );
nested.push(last_unsize_obligation); nested.push(last_unsize_obligation);
src = BuiltinImplSource::TupleUnsizing;
} }
_ => bug!("source: {source}, target: {target}"), _ => bug!("source: {source}, target: {target}"),
}; };
Ok(nested) Ok(ImplSource::Builtin(src, nested))
} }
fn confirm_const_destruct_candidate( fn confirm_const_destruct_candidate(

View file

@ -241,9 +241,9 @@ pub fn upcast_choices<'tcx>(
/// Given an upcast trait object described by `object`, returns the /// Given an upcast trait object described by `object`, returns the
/// index of the method `method_def_id` (which should be part of /// index of the method `method_def_id` (which should be part of
/// `object.upcast_trait_ref`) within the vtable for `object`. /// `object.upcast_trait_ref`) within the vtable for `object`.
pub fn get_vtable_index_of_object_method<'tcx, N>( pub fn get_vtable_index_of_object_method<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
object: &super::ImplSourceObjectData<N>, vtable_base: usize,
method_def_id: DefId, method_def_id: DefId,
) -> Option<usize> { ) -> Option<usize> {
// Count number of methods preceding the one we are selecting and // Count number of methods preceding the one we are selecting and
@ -252,7 +252,7 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
.iter() .iter()
.copied() .copied()
.position(|def_id| def_id == method_def_id) .position(|def_id| def_id == method_def_id)
.map(|index| object.vtable_base + index) .map(|index| vtable_base + index)
} }
pub fn closure_trait_ref_and_return_type<'tcx>( pub fn closure_trait_ref_and_return_type<'tcx>(

View file

@ -5,6 +5,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::traits::util::PredicateSet; use rustc_infer::traits::util::PredicateSet;
use rustc_infer::traits::ImplSource; use rustc_infer::traits::ImplSource;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::GenericArgs; use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
@ -384,8 +385,8 @@ pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
let trait_ref = ty::TraitRef::new(tcx, unsize_trait_did, [source, target]); let trait_ref = ty::TraitRef::new(tcx, unsize_trait_did, [source, target]);
match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) { match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) {
Ok(ImplSource::TraitUpcasting(implsrc_traitcasting)) => { Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, _)) => {
implsrc_traitcasting.vtable_vptr_slot *vtable_vptr_slot
} }
otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"), otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"),
} }

View file

@ -2,7 +2,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::traits::CodegenObligationError; use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt};
use rustc_span::sym; use rustc_span::sym;
@ -177,12 +177,15 @@ fn resolve_associated_item<'tcx>(
Some(ty::Instance::new(leaf_def.item.def_id, args)) Some(ty::Instance::new(leaf_def.item.def_id, args))
} }
traits::ImplSource::Object(ref data) => { traits::ImplSource::Builtin(BuiltinImplSource::Object { vtable_base }, _) => {
traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| { traits::get_vtable_index_of_object_method(tcx, *vtable_base, trait_item_id).map(
Instance { def: ty::InstanceDef::Virtual(trait_item_id, index), args: rcvr_args } |index| Instance {
}) def: ty::InstanceDef::Virtual(trait_item_id, index),
args: rcvr_args,
},
)
} }
traits::ImplSource::Builtin(..) => { traits::ImplSource::Builtin(BuiltinImplSource::Misc, _) => {
let lang_items = tcx.lang_items(); let lang_items = tcx.lang_items();
if Some(trait_ref.def_id) == lang_items.clone_trait() { if Some(trait_ref.def_id) == lang_items.clone_trait() {
// FIXME(eddyb) use lang items for methods instead of names. // FIXME(eddyb) use lang items for methods instead of names.
@ -291,8 +294,8 @@ fn resolve_associated_item<'tcx>(
} }
} }
traits::ImplSource::Param(..) traits::ImplSource::Param(..)
| traits::ImplSource::TraitUpcasting(_) | traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
| traits::ImplSource::TupleUnsizing(_) => None, | traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => None,
}) })
} }

View file

@ -14,7 +14,7 @@ use rustc_middle::mir::{
Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
Terminator, TerminatorKind, Terminator, TerminatorKind,
}; };
use rustc_middle::traits::{ImplSource, ObligationCause}; use rustc_middle::traits::{ImplSource, ObligationCause, BuiltinImplSource};
use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt}; use rustc_middle::ty::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt};
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
@ -411,7 +411,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
if !matches!( if !matches!(
impl_src, impl_src,
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst) ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
) { ) {
return false; return false;
} }