mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Make everything builtin!
This commit is contained in:
parent
de81007d13
commit
a7ed9c1da7
@ -8,6 +8,7 @@ use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericArgKind, GenericArgs};
|
||||
use rustc_middle::ty::{TraitRef, TypeVisitableExt};
|
||||
@ -766,7 +767,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
};
|
||||
|
||||
match implsrc {
|
||||
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
|
||||
Ok(Some(ImplSource::Param(ty::BoundConstness::ConstIfConst, _))) => {
|
||||
debug!(
|
||||
"const_trait_impl: provided {:?} via where-clause in {:?}",
|
||||
trait_ref, param_env
|
||||
@ -774,7 +775,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
return;
|
||||
}
|
||||
// Closure: Fn{Once|Mut}
|
||||
Ok(Some(ImplSource::Builtin(_)))
|
||||
Ok(Some(ImplSource::Builtin(BuiltinImplSource::Misc, _)))
|
||||
if trait_ref.self_ty().is_closure()
|
||||
&& tcx.fn_trait_kind_from_def_id(trait_id).is_some() =>
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
|
||||
use rustc_trait_selection::traits::{
|
||||
self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
|
||||
@ -172,7 +173,8 @@ impl Qualif for NeedsNonConstDrop {
|
||||
|
||||
if !matches!(
|
||||
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,
|
||||
// then it's bad
|
||||
|
@ -46,6 +46,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
|
||||
use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
|
||||
use rustc_infer::traits::{Obligation, PredicateObligation};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::adjustment::{
|
||||
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
|
||||
};
|
||||
@ -687,12 +688,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
}
|
||||
|
||||
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 {
|
||||
traits::ImplSource::TraitUpcasting(..) => {
|
||||
traits::ImplSource::Builtin(
|
||||
BuiltinImplSource::TraitUpcasting { .. },
|
||||
_,
|
||||
) => {
|
||||
has_trait_upcasting_coercion =
|
||||
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;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -43,7 +43,7 @@ macro_rules! span_bug {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! CloneLiftImpls {
|
||||
($($ty:ty,)+) => {
|
||||
($($ty:ty),+ $(,)?) => {
|
||||
$(
|
||||
impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
|
||||
type Lifted = Self;
|
||||
@ -59,7 +59,7 @@ macro_rules! CloneLiftImpls {
|
||||
/// allocated data** (i.e., don't need to be folded).
|
||||
#[macro_export]
|
||||
macro_rules! TrivialTypeTraversalImpls {
|
||||
($($ty:ty,)+) => {
|
||||
($($ty: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>>>(
|
||||
|
@ -178,9 +178,7 @@ impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
Cache,
|
||||
}
|
||||
TrivialTypeTraversalAndLiftImpls! { Cache }
|
||||
|
||||
impl<S: Encoder> Encodable<S> for Cache {
|
||||
#[inline]
|
||||
|
@ -66,9 +66,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
ErrorHandled,
|
||||
}
|
||||
TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
|
||||
|
||||
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
|
||||
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
||||
|
@ -706,9 +706,7 @@ pub enum BindingForm<'tcx> {
|
||||
RefForGuard,
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
BindingForm<'tcx>,
|
||||
}
|
||||
TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx> }
|
||||
|
||||
mod binding_form_impl {
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
|
@ -649,46 +649,31 @@ pub enum ImplSource<'tcx, N> {
|
||||
/// for some type parameter. The `Vec<N>` represents the
|
||||
/// obligations incurred from normalizing the where-clause (if
|
||||
/// any).
|
||||
Param(Vec<N>, ty::BoundConstness),
|
||||
Param(ty::BoundConstness, Vec<N>),
|
||||
|
||||
/// Virtual calls through an object.
|
||||
Object(ImplSourceObjectData<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>),
|
||||
/// Successful resolution for a builtin impl.
|
||||
Builtin(BuiltinImplSource, Vec<N>),
|
||||
}
|
||||
|
||||
impl<'tcx, N> ImplSource<'tcx, N> {
|
||||
pub fn nested_obligations(self) -> Vec<N> {
|
||||
match self {
|
||||
ImplSource::UserDefined(i) => i.nested,
|
||||
ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => n,
|
||||
ImplSource::Object(d) => d.nested,
|
||||
ImplSource::TraitUpcasting(d) => d.nested,
|
||||
ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_nested_obligations(&self) -> &[N] {
|
||||
match self {
|
||||
ImplSource::UserDefined(i) => &i.nested,
|
||||
ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => &n,
|
||||
ImplSource::Object(d) => &d.nested,
|
||||
ImplSource::TraitUpcasting(d) => &d.nested,
|
||||
ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => &n,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] {
|
||||
match self {
|
||||
ImplSource::UserDefined(i) => &mut i.nested,
|
||||
ImplSource::Param(n, _) | ImplSource::Builtin(n) | ImplSource::TupleUnsizing(n) => n,
|
||||
ImplSource::Object(d) => &mut d.nested,
|
||||
ImplSource::TraitUpcasting(d) => &mut d.nested,
|
||||
ImplSource::Param(_, n) | ImplSource::Builtin(_, n) => n,
|
||||
}
|
||||
}
|
||||
|
||||
@ -702,20 +687,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
|
||||
args: i.args,
|
||||
nested: i.nested.into_iter().map(f).collect(),
|
||||
}),
|
||||
ImplSource::Param(n, ct) => ImplSource::Param(n.into_iter().map(f).collect(), ct),
|
||||
ImplSource::Builtin(n) => ImplSource::Builtin(n.into_iter().map(f).collect()),
|
||||
ImplSource::TupleUnsizing(n) => {
|
||||
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(),
|
||||
})
|
||||
ImplSource::Param(ct, n) => ImplSource::Param(ct, n.into_iter().map(f).collect()),
|
||||
ImplSource::Builtin(source, n) => {
|
||||
ImplSource::Builtin(source, n.into_iter().map(f).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -739,30 +713,32 @@ pub struct ImplSourceUserDefinedData<'tcx, N> {
|
||||
pub nested: Vec<N>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ImplSourceTraitUpcastingData<N> {
|
||||
/// The vtable is formed by concatenating together the method lists of
|
||||
/// 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.
|
||||
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> {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Debug)]
|
||||
pub enum BuiltinImplSource {
|
||||
/// Some builtin impl we don't need to differentiate. This should be used
|
||||
/// unless more specific information is necessary.
|
||||
Misc,
|
||||
/// A builtin impl for trait objects.
|
||||
///
|
||||
/// The vtable is formed by concatenating together the method lists of
|
||||
/// 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
|
||||
/// in that vtable.
|
||||
pub vtable_base: usize,
|
||||
|
||||
pub nested: Vec<N>,
|
||||
Object { vtable_base: usize },
|
||||
/// The vtable is formed by concatenating together the method lists of
|
||||
/// 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)]
|
||||
pub enum ObjectSafetyViolation {
|
||||
/// `Self: Sized` declared on the trait.
|
||||
|
@ -304,9 +304,7 @@ impl From<ErrorGuaranteed> for OverflowError {
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
OverflowError,
|
||||
}
|
||||
TrivialTypeTraversalAndLiftImpls! { OverflowError }
|
||||
|
||||
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
||||
fn from(overflow_error: OverflowError) -> SelectionError<'tcx> {
|
||||
|
@ -6,20 +6,16 @@ use std::fmt;
|
||||
|
||||
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v),
|
||||
match self {
|
||||
super::ImplSource::UserDefined(v) => write!(f, "{:?}", v),
|
||||
|
||||
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::Param(ref n, ct) => {
|
||||
write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
|
||||
super::ImplSource::Builtin(source, d) => {
|
||||
write!(f, "Builtin({source:?}, {d:?})")
|
||||
}
|
||||
|
||||
super::ImplSource::TupleUnsizing(ref d) => write!(f, "{:?}", d),
|
||||
|
||||
super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
|
||||
super::ImplSource::Param(ct, n) => {
|
||||
write!(f, "ImplSourceParamData({:?}, {:?})", n, ct)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -27,9 +27,7 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
|
||||
}
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! {
|
||||
NotConstEvaluatable,
|
||||
}
|
||||
TrivialTypeTraversalAndLiftImpls! { NotConstEvaluatable }
|
||||
|
||||
pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;
|
||||
|
||||
|
@ -6,7 +6,7 @@ pub enum BindingMode {
|
||||
BindByValue(Mutability),
|
||||
}
|
||||
|
||||
TrivialTypeTraversalAndLiftImpls! { BindingMode, }
|
||||
TrivialTypeTraversalAndLiftImpls! { BindingMode }
|
||||
|
||||
impl BindingMode {
|
||||
pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
|
||||
|
@ -3,17 +3,16 @@
|
||||
use super::search_graph::OverflowHandler;
|
||||
use super::{EvalCtxt, SolverMode};
|
||||
use crate::traits::coherence;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::util::elaborate;
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_middle::traits::solve::inspect::CandidateKind;
|
||||
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::TypeVisitableExt;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{fast_reject, TypeFoldable};
|
||||
use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use std::fmt::Debug;
|
||||
|
||||
@ -89,17 +88,6 @@ pub(super) enum CandidateSource {
|
||||
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.
|
||||
pub(super) trait GoalKind<'tcx>:
|
||||
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
|
||||
@ -282,20 +270,6 @@ pub(super) trait GoalKind<'tcx>:
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> 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(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
@ -310,6 +284,25 @@ pub(super) trait GoalKind<'tcx>:
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> 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> {
|
||||
@ -343,7 +336,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
) -> Option<Vec<Candidate<'tcx>>> {
|
||||
goal.predicate.self_ty().is_ty_var().then(|| {
|
||||
vec![Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
result: self
|
||||
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
.unwrap(),
|
||||
@ -412,7 +405,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
Certainty::Maybe(MaybeCause::Overflow),
|
||||
)?;
|
||||
Ok(vec![Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
result,
|
||||
}])
|
||||
},
|
||||
@ -848,29 +841,47 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
ty::Dynamic(bounds, ..) => bounds,
|
||||
};
|
||||
|
||||
let own_bounds: FxIndexSet<_> =
|
||||
bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty)).collect();
|
||||
for assumption in elaborate(tcx, own_bounds.iter().copied())
|
||||
// we only care about bounds that match the `Self` type
|
||||
.filter_only_self()
|
||||
{
|
||||
// FIXME: Predicates are fully elaborated in the object type's existential bounds
|
||||
// list. We want to only consider these pre-elaborated projections, and not other
|
||||
// projection predicates that we reach by elaborating the principal trait ref,
|
||||
// since that'll cause ambiguity.
|
||||
//
|
||||
// We can remove this when we have implemented lifetime intersections in responses.
|
||||
if assumption.as_projection_clause().is_some() && !own_bounds.contains(&assumption) {
|
||||
continue;
|
||||
// Consider all of the auto-trait and projection bounds, which don't
|
||||
// need to be recorded as a `BuiltinImplSource::Object` since they don't
|
||||
// really have a vtable base...
|
||||
for bound in bounds {
|
||||
match bound.skip_binder() {
|
||||
ty::ExistentialPredicate::Trait(_) => {
|
||||
// Skip principal
|
||||
}
|
||||
ty::ExistentialPredicate::Projection(_)
|
||||
| ty::ExistentialPredicate::AutoTrait(_) => {
|
||||
match G::consider_object_bound_candidate(
|
||||
self,
|
||||
goal,
|
||||
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) {
|
||||
Ok(result) => candidates.push(Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Object),
|
||||
result,
|
||||
}),
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
// FIXME: We only need to do *any* of this if we're considering a trait goal,
|
||||
// since we don't need to look at any supertrait or anything if we are doing
|
||||
// a projection goal.
|
||||
if let Some(principal) = bounds.principal() {
|
||||
let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
|
||||
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)
|
||||
{
|
||||
Ok(result) => candidates.push(Candidate {
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Ambiguity),
|
||||
source: CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
|
||||
result,
|
||||
}),
|
||||
// FIXME: This will be reachable at some point if we're in
|
||||
|
@ -25,6 +25,7 @@ use std::io::Write;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::traits::specialization_graph;
|
||||
use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
|
||||
|
||||
use super::inspect::ProofTreeBuilder;
|
||||
use super::search_graph::{self, OverflowHandler};
|
||||
@ -920,4 +921,39 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
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(())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,20 @@
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt};
|
||||
use rustc_infer::traits::{
|
||||
Obligation, PolyTraitObligation, PredicateObligation, Selection, SelectionResult, TraitEngine,
|
||||
};
|
||||
use rustc_middle::traits::solve::{CanonicalInput, Certainty, Goal};
|
||||
use rustc_middle::traits::{
|
||||
ImplSource, ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
|
||||
ObligationCause, SelectionError,
|
||||
BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, ObligationCause, SelectionError,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
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::inspect::ProofTreeBuilder;
|
||||
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::TraitEngineExt;
|
||||
|
||||
@ -105,47 +100,26 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
|
||||
rematch_impl(self, goal, def_id, nested_obligations)
|
||||
}
|
||||
|
||||
// Rematching the dyn upcast or object goal will instantiate the same nested
|
||||
// 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))
|
||||
(Certainty::Maybe(_), CandidateSource::BuiltinImpl(src))
|
||||
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
|
||||
// `Certainty::Yes`, then they should've all been verified and don't
|
||||
// need re-checking.
|
||||
(Certainty::Yes, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc)) => {
|
||||
Ok(Some(ImplSource::Builtin(nested_obligations)))
|
||||
(Certainty::Yes, CandidateSource::BuiltinImpl(src)) => {
|
||||
Ok(Some(ImplSource::Builtin(src, nested_obligations)))
|
||||
}
|
||||
|
||||
// It's fine not to do anything to rematch these, since there are no
|
||||
// nested obligations.
|
||||
(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,
|
||||
|
||||
// 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,
|
||||
(_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object)) => true,
|
||||
(_, CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. })) => true,
|
||||
|
||||
(CandidateSource::Impl(victim_def_id), CandidateSource::Impl(other_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 })))
|
||||
}
|
||||
|
||||
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.
|
||||
/// 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.
|
||||
@ -343,6 +216,7 @@ fn rematch_unsize<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
|
||||
mut nested: Vec<PredicateObligation<'tcx>>,
|
||||
source: BuiltinImplSource,
|
||||
) -> SelectionResult<'tcx, Selection<'tcx>> {
|
||||
let tcx = infcx.tcx;
|
||||
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,
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)),
|
||||
));
|
||||
|
||||
Ok(Some(ImplSource::Builtin(source, nested)))
|
||||
}
|
||||
// `[T; n]` -> `[T]` unsizing
|
||||
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
|
||||
@ -389,6 +265,8 @@ fn rematch_unsize<'tcx>(
|
||||
.expect("expected rematch to succeed")
|
||||
.into_obligations(),
|
||||
);
|
||||
|
||||
Ok(Some(ImplSource::Builtin(source, nested)))
|
||||
}
|
||||
// Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
|
||||
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
|
||||
@ -439,6 +317,8 @@ fn rematch_unsize<'tcx>(
|
||||
goal.param_env,
|
||||
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>`
|
||||
(&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.
|
||||
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:
|
||||
// 1. the certainty is `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>(
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::traits::specialization_graph;
|
||||
|
||||
use super::assembly::{self, structural_traits, BuiltinImplSource};
|
||||
use super::assembly::{self, structural_traits};
|
||||
use super::EvalCtxt;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -10,6 +10,7 @@ use rustc_infer::traits::specialization_graph::LeafDef;
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_middle::traits::solve::inspect::CandidateKind;
|
||||
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::ProjectionPredicate;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
@ -1,15 +1,14 @@
|
||||
//! 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::{EvalCtxt, SolverMode};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{LangItem, Movability};
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_middle::traits::solve::inspect::CandidateKind;
|
||||
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::Reveal;
|
||||
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
|
||||
use rustc_middle::traits::{BuiltinImplSource, Reveal};
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
|
||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
|
||||
@ -382,37 +381,48 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
let b_ty = match ecx
|
||||
.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(_) => {
|
||||
return vec![(
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
Ok(Some(b_ty)) => {
|
||||
// If we have a type var, then bail with ambiguity.
|
||||
if b_ty.is_ty_var() {
|
||||
return vec![(
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::AMBIGUOUS,
|
||||
)
|
||||
.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![],
|
||||
};
|
||||
|
||||
let mut results = vec![];
|
||||
results.extend(ecx.consider_builtin_dyn_upcast_candidates(goal.param_env, a_ty, b_ty));
|
||||
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()
|
||||
.map(|resp| (resp, BuiltinImplSource::TraitUpcasting)),
|
||||
);
|
||||
results.extend(
|
||||
ecx.consider_builtin_unsize_candidate(goal.param_env, a_ty, b_ty).into_iter().map(
|
||||
|resp| {
|
||||
.map(|resp| {
|
||||
// If we're unsizing from tuple -> tuple, detect
|
||||
let source =
|
||||
if matches!((a_ty.kind(), b_ty.kind()), (ty::Tuple(..), ty::Tuple(..)))
|
||||
{
|
||||
BuiltinImplSource::TupleUnsize
|
||||
BuiltinImplSource::TupleUnsizing
|
||||
} else {
|
||||
BuiltinImplSource::Misc
|
||||
};
|
||||
(resp, source)
|
||||
},
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
results
|
||||
@ -484,10 +494,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
fn consider_builtin_unsize_candidate(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
a_ty: Ty<'tcx>,
|
||||
b_ty: Ty<'tcx>,
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let Goal { param_env, predicate: (a_ty, b_ty) } = goal;
|
||||
self.probe_candidate("builtin unsize").enter(|ecx| {
|
||||
let tcx = ecx.tcx();
|
||||
match (a_ty.kind(), b_ty.kind()) {
|
||||
@ -614,7 +623,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
a_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() {
|
||||
bug!("unexpected type variable in unsize goal")
|
||||
}
|
||||
@ -634,57 +643,64 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let mut unsize_dyn_to_principal = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
|
||||
self.probe_candidate("upcast dyn to principle").enter(|ecx| -> Result<_, NoSolution> {
|
||||
// Require that all of the trait predicates from A match B, except for
|
||||
// the auto traits. We do this by constructing a new A type with B's
|
||||
// auto traits, and equating these types.
|
||||
let new_a_data = principal
|
||||
.into_iter()
|
||||
.map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait))
|
||||
.chain(a_data.iter().filter(|a| {
|
||||
matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_))
|
||||
}))
|
||||
.chain(
|
||||
b_data
|
||||
.auto_traits()
|
||||
.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);
|
||||
// Try to match `a_ty` against `b_ty`, replacing `a_ty`'s principal trait ref with
|
||||
// the supertrait principal and subtyping the types.
|
||||
let unsize_dyn_to_principal =
|
||||
|ecx: &mut Self, principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
|
||||
ecx.probe_candidate("upcast dyn to principle").enter(
|
||||
|ecx| -> Result<_, NoSolution> {
|
||||
// Require that all of the trait predicates from A match B, except for
|
||||
// the auto traits. We do this by constructing a new A type with B's
|
||||
// auto traits, and equating these types.
|
||||
let new_a_data = principal
|
||||
.into_iter()
|
||||
.map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait))
|
||||
.chain(a_data.iter().filter(|a| {
|
||||
matches!(a.skip_binder(), ty::ExistentialPredicate::Projection(_))
|
||||
}))
|
||||
.chain(
|
||||
b_data
|
||||
.auto_traits()
|
||||
.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.
|
||||
ecx.eq(param_env, new_a_ty, b_ty)?;
|
||||
ecx.add_goal(Goal::new(
|
||||
tcx,
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
|
||||
));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
};
|
||||
// We also require that A's lifetime outlives B's lifetime.
|
||||
ecx.eq(param_env, new_a_ty, b_ty)?;
|
||||
ecx.add_goal(Goal::new(
|
||||
tcx,
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
|
||||
));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
let mut responses = vec![];
|
||||
// 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).
|
||||
if a_data.principal_def_id() == b_data.principal_def_id() {
|
||||
if let Ok(response) = unsize_dyn_to_principal(a_data.principal()) {
|
||||
responses.push(response);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
if let Ok(resp) = unsize_dyn_to_principal(self, a_data.principal()) {
|
||||
responses.push((resp, BuiltinImplSource::Misc));
|
||||
}
|
||||
} 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
|
||||
|
@ -4,7 +4,6 @@ use super::check_args_compatible;
|
||||
use super::specialization_graph;
|
||||
use super::translate_args;
|
||||
use super::util;
|
||||
use super::ImplSourceUserDefinedData;
|
||||
use super::MismatchedProjectionTypes;
|
||||
use super::Obligation;
|
||||
use super::ObligationCause;
|
||||
@ -13,6 +12,9 @@ use super::Selection;
|
||||
use super::SelectionContext;
|
||||
use super::SelectionError;
|
||||
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::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
@ -1717,7 +1719,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
};
|
||||
|
||||
let eligible = match &impl_source {
|
||||
super::ImplSource::UserDefined(impl_data) => {
|
||||
ImplSource::UserDefined(impl_data) => {
|
||||
// We have to be careful when projecting out of an
|
||||
// impl because of specialization. If we are not in
|
||||
// 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
|
||||
// be known. Any type with multiple potential associated types is therefore
|
||||
// not eligible.
|
||||
@ -1891,7 +1893,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
bug!("unexpected builtin trait with associated type: {trait_ref:?}")
|
||||
}
|
||||
}
|
||||
super::ImplSource::Param(..) => {
|
||||
ImplSource::Param(..) => {
|
||||
// This case tell us nothing about the value of an
|
||||
// associated type. Consider:
|
||||
//
|
||||
@ -1919,14 +1921,14 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
||||
// in `assemble_candidates_from_param_env`.
|
||||
false
|
||||
}
|
||||
super::ImplSource::Object(_) => {
|
||||
ImplSource::Builtin(BuiltinImplSource::Object { .. }, _) => {
|
||||
// Handled by the `Object` projection candidate. See
|
||||
// `assemble_candidates_from_object_ty` for an explanation of
|
||||
// why we special case object types.
|
||||
false
|
||||
}
|
||||
super::ImplSource::TraitUpcasting(_)
|
||||
| super::ImplSource::TupleUnsizing(_) => {
|
||||
ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
|
||||
| ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
|
||||
// These traits have no associated types.
|
||||
selcx.tcx().sess.delay_span_bug(
|
||||
obligation.cause.span,
|
||||
@ -1986,8 +1988,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
||||
impl_source: Selection<'tcx>,
|
||||
) -> Progress<'tcx> {
|
||||
match impl_source {
|
||||
super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
|
||||
super::ImplSource::Builtin(data) => {
|
||||
ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data) => {
|
||||
let trait_def_id = obligation.predicate.trait_def_id(selcx.tcx());
|
||||
let lang_items = selcx.tcx().lang_items();
|
||||
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)
|
||||
}
|
||||
}
|
||||
super::ImplSource::Object(_)
|
||||
| super::ImplSource::Param(..)
|
||||
| super::ImplSource::TraitUpcasting(_)
|
||||
| super::ImplSource::TupleUnsizing(_) => {
|
||||
ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)
|
||||
| ImplSource::Param(..)
|
||||
| ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
|
||||
| ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
|
||||
// we don't create Select candidates with this kind of resolution
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
|
@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
|
||||
use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
|
||||
use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch};
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
|
||||
TraitPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt,
|
||||
@ -26,9 +26,9 @@ use crate::traits::vtable::{
|
||||
};
|
||||
use crate::traits::{
|
||||
BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
|
||||
ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized,
|
||||
Obligation, ObligationCause, OutputTypeParameterMismatch, PolyTraitObligation,
|
||||
PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, Unimplemented,
|
||||
ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
|
||||
OutputTypeParameterMismatch, PolyTraitObligation, PredicateObligation, Selection,
|
||||
SelectionError, TraitNotObjectSafe, Unimplemented,
|
||||
};
|
||||
|
||||
use super::BuiltinImplConditions;
|
||||
@ -48,18 +48,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
let mut impl_src = match candidate {
|
||||
BuiltinCandidate { has_nested } => {
|
||||
let data = self.confirm_builtin_candidate(obligation, has_nested);
|
||||
ImplSource::Builtin(data)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
TransmutabilityCandidate => {
|
||||
let data = self.confirm_transmutability_candidate(obligation)?;
|
||||
ImplSource::Builtin(data)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
ParamCandidate(param) => {
|
||||
let obligations =
|
||||
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) => {
|
||||
@ -68,76 +68,57 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
AutoImplCandidate => {
|
||||
let data = self.confirm_auto_impl_candidate(obligation)?;
|
||||
ImplSource::Builtin(data)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
ProjectionCandidate(idx, constness) => {
|
||||
let obligations = self.confirm_projection_candidate(obligation, idx)?;
|
||||
ImplSource::Param(obligations, constness)
|
||||
ImplSource::Param(constness, obligations)
|
||||
}
|
||||
|
||||
ObjectCandidate(idx) => {
|
||||
let data = self.confirm_object_candidate(obligation, idx)?;
|
||||
ImplSource::Object(data)
|
||||
}
|
||||
ObjectCandidate(idx) => self.confirm_object_candidate(obligation, idx)?,
|
||||
|
||||
ClosureCandidate { .. } => {
|
||||
let vtable_closure = self.confirm_closure_candidate(obligation)?;
|
||||
ImplSource::Builtin(vtable_closure)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
|
||||
}
|
||||
|
||||
GeneratorCandidate => {
|
||||
let vtable_generator = self.confirm_generator_candidate(obligation)?;
|
||||
ImplSource::Builtin(vtable_generator)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_generator)
|
||||
}
|
||||
|
||||
FutureCandidate => {
|
||||
let vtable_future = self.confirm_future_candidate(obligation)?;
|
||||
ImplSource::Builtin(vtable_future)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_future)
|
||||
}
|
||||
|
||||
FnPointerCandidate { is_const } => {
|
||||
let data = self.confirm_fn_pointer_candidate(obligation, is_const)?;
|
||||
ImplSource::Builtin(data)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
TraitAliasCandidate => {
|
||||
let data = self.confirm_trait_alias_candidate(obligation);
|
||||
ImplSource::Builtin(data)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||
}
|
||||
|
||||
BuiltinObjectCandidate => {
|
||||
// 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
|
||||
// no additional obligations to prove and no types in particular to unify, etc.
|
||||
ImplSource::Builtin(Vec::new())
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, Vec::new())
|
||||
}
|
||||
|
||||
BuiltinUnsizeCandidate => {
|
||||
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)
|
||||
}
|
||||
}
|
||||
BuiltinUnsizeCandidate => self.confirm_builtin_unsize_candidate(obligation)?,
|
||||
|
||||
TraitUpcastingUnsizeCandidate(idx) => {
|
||||
let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
|
||||
ImplSource::TraitUpcasting(data)
|
||||
self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?
|
||||
}
|
||||
|
||||
ConstDestructCandidate(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,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
index: usize,
|
||||
) -> Result<ImplSourceObjectData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
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)),
|
||||
);
|
||||
|
||||
Ok(ImplSourceObjectData { vtable_base, nested })
|
||||
Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested))
|
||||
}
|
||||
|
||||
fn confirm_fn_pointer_candidate(
|
||||
@ -909,7 +890,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
idx: usize,
|
||||
) -> Result<ImplSourceTraitUpcastingData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
// `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 =
|
||||
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(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
source: Ty<'tcx>,
|
||||
target: Ty<'tcx>,
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'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");
|
||||
|
||||
let mut nested = vec![];
|
||||
let src;
|
||||
match (source.kind(), target.kind()) {
|
||||
// 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))
|
||||
@ -1062,6 +1048,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
obligation.param_env,
|
||||
obligation.predicate.rebind(outlives),
|
||||
));
|
||||
|
||||
src = BuiltinImplSource::Misc;
|
||||
}
|
||||
|
||||
// `T` -> `Trait`
|
||||
@ -1108,6 +1096,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
nested.push(predicate_to_obligation(
|
||||
ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx),
|
||||
));
|
||||
|
||||
src = BuiltinImplSource::Misc;
|
||||
}
|
||||
|
||||
// `[T; n]` -> `[T]`
|
||||
@ -1118,6 +1108,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
.eq(DefineOpaqueTypes::No, b, a)
|
||||
.map_err(|_| Unimplemented)?;
|
||||
nested.extend(obligations);
|
||||
|
||||
src = BuiltinImplSource::Misc;
|
||||
}
|
||||
|
||||
// `Struct<T>` -> `Struct<U>`
|
||||
@ -1174,6 +1166,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
),
|
||||
);
|
||||
nested.push(tail_unsize_obligation);
|
||||
|
||||
src = BuiltinImplSource::Misc;
|
||||
}
|
||||
|
||||
// `(.., T)` -> `(.., U)`
|
||||
@ -1201,12 +1195,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]),
|
||||
);
|
||||
nested.push(last_unsize_obligation);
|
||||
|
||||
src = BuiltinImplSource::TupleUnsizing;
|
||||
}
|
||||
|
||||
_ => bug!("source: {source}, target: {target}"),
|
||||
};
|
||||
|
||||
Ok(nested)
|
||||
Ok(ImplSource::Builtin(src, nested))
|
||||
}
|
||||
|
||||
fn confirm_const_destruct_candidate(
|
||||
|
@ -241,9 +241,9 @@ pub fn upcast_choices<'tcx>(
|
||||
/// Given an upcast trait object described by `object`, returns the
|
||||
/// index of the method `method_def_id` (which should be part of
|
||||
/// `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>,
|
||||
object: &super::ImplSourceObjectData<N>,
|
||||
vtable_base: usize,
|
||||
method_def_id: DefId,
|
||||
) -> Option<usize> {
|
||||
// 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()
|
||||
.copied()
|
||||
.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>(
|
||||
|
@ -5,6 +5,7 @@ use rustc_hir::lang_items::LangItem;
|
||||
use rustc_infer::traits::util::PredicateSet;
|
||||
use rustc_infer::traits::ImplSource;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::visit::TypeVisitableExt;
|
||||
use rustc_middle::ty::GenericArgs;
|
||||
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]);
|
||||
|
||||
match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) {
|
||||
Ok(ImplSource::TraitUpcasting(implsrc_traitcasting)) => {
|
||||
implsrc_traitcasting.vtable_vptr_slot
|
||||
Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { vtable_vptr_slot }, _)) => {
|
||||
*vtable_vptr_slot
|
||||
}
|
||||
otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"),
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
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::{self, Instance, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::sym;
|
||||
@ -177,12 +177,15 @@ fn resolve_associated_item<'tcx>(
|
||||
|
||||
Some(ty::Instance::new(leaf_def.item.def_id, args))
|
||||
}
|
||||
traits::ImplSource::Object(ref data) => {
|
||||
traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| {
|
||||
Instance { def: ty::InstanceDef::Virtual(trait_item_id, index), args: rcvr_args }
|
||||
})
|
||||
traits::ImplSource::Builtin(BuiltinImplSource::Object { vtable_base }, _) => {
|
||||
traits::get_vtable_index_of_object_method(tcx, *vtable_base, trait_item_id).map(
|
||||
|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();
|
||||
if Some(trait_ref.def_id) == lang_items.clone_trait() {
|
||||
// FIXME(eddyb) use lang items for methods instead of names.
|
||||
@ -291,8 +294,8 @@ fn resolve_associated_item<'tcx>(
|
||||
}
|
||||
}
|
||||
traits::ImplSource::Param(..)
|
||||
| traits::ImplSource::TraitUpcasting(_)
|
||||
| traits::ImplSource::TupleUnsizing(_) => None,
|
||||
| traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
|
||||
| traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ use rustc_middle::mir::{
|
||||
Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
|
||||
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::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt};
|
||||
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!(
|
||||
impl_src,
|
||||
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user