Make everything builtin!
This commit is contained in:
parent
de81007d13
commit
a7ed9c1da7
23 changed files with 345 additions and 444 deletions
|
@ -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() =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -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>>>(
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(())
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>(
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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>(
|
||||||
|
|
|
@ -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:?}"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue