Uplift the new trait solver

This commit is contained in:
Michael Goulet 2024-06-17 17:59:08 -04:00
parent baf94bddf0
commit 532149eb88
36 changed files with 2014 additions and 1457 deletions

View File

@ -4520,7 +4520,16 @@ dependencies = [
name = "rustc_next_trait_solver"
version = "0.0.0"
dependencies = [
"bitflags 2.5.0",
"derivative",
"rustc_ast_ir",
"rustc_data_structures",
"rustc_index",
"rustc_macros",
"rustc_serialize",
"rustc_type_ir",
"rustc_type_ir_macros",
"tracing",
]
[[package]]

View File

@ -205,6 +205,14 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
self.did()
}
fn is_struct(self) -> bool {
self.is_struct()
}
fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
Some(interner.type_of(self.non_enum_variant().tail_opt()?.did))
}
fn is_phantom_data(self) -> bool {
self.is_phantom_data()
}
@ -212,7 +220,7 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
fn all_field_tys(
self,
tcx: TyCtxt<'tcx>,
) -> ty::EarlyBinder<'tcx, impl Iterator<Item = Ty<'tcx>>> {
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = Ty<'tcx>>> {
ty::EarlyBinder::bind(
self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()),
)

View File

@ -16,8 +16,8 @@ mod valtree;
pub use int::*;
pub use kind::*;
use rustc_span::Span;
use rustc_span::DUMMY_SP;
use rustc_span::{ErrorGuaranteed, Span};
pub use valtree::*;
pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
@ -176,6 +176,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self {
Const::new_expr(interner, expr)
}
fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
Const::new_error(interner, guar)
}
}
impl<'tcx> Const<'tcx> {

View File

@ -90,46 +90,65 @@ use std::ops::{Bound, Deref};
impl<'tcx> Interner for TyCtxt<'tcx> {
type DefId = DefId;
type LocalDefId = LocalDefId;
type AdtDef = ty::AdtDef<'tcx>;
type GenericArgs = ty::GenericArgsRef<'tcx>;
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
type GenericArg = ty::GenericArg<'tcx>;
type Term = ty::Term<'tcx>;
type BoundVarKinds = &'tcx List<ty::BoundVariableKind>;
type BoundVarKind = ty::BoundVariableKind;
type CanonicalVars = CanonicalVarInfos<'tcx>;
type BoundVarKind = ty::BoundVariableKind;
type PredefinedOpaques = solve::PredefinedOpaques<'tcx>;
fn mk_predefined_opaques_in_body(
self,
data: PredefinedOpaquesData<Self>,
) -> Self::PredefinedOpaques {
self.mk_predefined_opaques_in_body(data)
}
type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
type ExternalConstraints = ExternalConstraints<'tcx>;
type CanonicalGoalEvaluationStepRef =
&'tcx solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>;
type CanonicalVars = CanonicalVarInfos<'tcx>;
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
self.mk_canonical_var_infos(infos)
}
type ExternalConstraints = ExternalConstraints<'tcx>;
fn mk_external_constraints(
self,
data: ExternalConstraintsData<Self>,
) -> ExternalConstraints<'tcx> {
self.mk_external_constraints(data)
}
type DepNodeIndex = DepNodeIndex;
fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) {
self.dep_graph.with_anon_task(self, crate::dep_graph::dep_kinds::TraitSelect, task)
}
type Ty = Ty<'tcx>;
type Tys = &'tcx List<Ty<'tcx>>;
type FnInputTys = &'tcx [Ty<'tcx>];
type ParamTy = ParamTy;
type BoundTy = ty::BoundTy;
type PlaceholderTy = ty::PlaceholderType;
type PlaceholderTy = ty::PlaceholderType;
type ErrorGuaranteed = ErrorGuaranteed;
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
type AllocId = crate::mir::interpret::AllocId;
type AllocId = crate::mir::interpret::AllocId;
type Pat = Pattern<'tcx>;
type Safety = hir::Safety;
type Abi = abi::Abi;
type Const = ty::Const<'tcx>;
type PlaceholderConst = ty::PlaceholderConst;
type ParamConst = ty::ParamConst;
type BoundConst = ty::BoundVar;
type ValueConst = ty::ValTree<'tcx>;
type ExprConst = ty::Expr<'tcx>;
type Region = Region<'tcx>;
type EarlyParamRegion = ty::EarlyParamRegion;
type LateParamRegion = ty::LateParamRegion;
type BoundRegion = ty::BoundRegion;
@ -137,15 +156,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type ParamEnv = ty::ParamEnv<'tcx>;
type Predicate = Predicate<'tcx>;
type Clause = Clause<'tcx>;
type Clauses = ty::Clauses<'tcx>;
type DepNodeIndex = DepNodeIndex;
fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) {
self.dep_graph.with_anon_task(self, crate::dep_graph::dep_kinds::TraitSelect, task)
}
type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>;
fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> {
match mode {
SolverMode::Normal => &self.new_solver_evaluation_cache,
@ -157,17 +173,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.expand_abstract_consts(t)
}
fn mk_external_constraints(
self,
data: ExternalConstraintsData<Self>,
) -> ExternalConstraints<'tcx> {
self.mk_external_constraints(data)
}
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
self.mk_canonical_var_infos(infos)
}
type GenericsOf = &'tcx ty::Generics;
fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics {
@ -184,6 +189,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.type_of(def_id)
}
type AdtDef = ty::AdtDef<'tcx>;
fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {
self.adt_def(adt_def_id)
}
fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
match self.def_kind(alias.def_id) {
DefKind::AssocTy => {
@ -221,8 +231,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
fn trait_ref_and_own_args_for_alias(
self,
def_id: DefId,
args: Self::GenericArgs,
) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
args: ty::GenericArgsRef<'tcx>,
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
let trait_def_id = self.parent(def_id);
assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
@ -233,18 +243,22 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
)
}
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs {
fn mk_args(self, args: &[Self::GenericArg]) -> ty::GenericArgsRef<'tcx> {
self.mk_args(args)
}
fn mk_args_from_iter<I, T>(self, args: I) -> T::Output
where
I: Iterator<Item = T>,
T: CollectAndApply<Self::GenericArg, Self::GenericArgs>,
T: CollectAndApply<Self::GenericArg, ty::GenericArgsRef<'tcx>>,
{
self.mk_args_from_iter(args)
}
fn check_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> bool {
self.check_args_compatible(def_id, args)
}
fn check_and_mk_args(
self,
def_id: DefId,
@ -263,7 +277,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
where
I: Iterator<Item = T>,
T: CollectAndApply<Self::Ty, Self::Tys>,
T: CollectAndApply<Ty<'tcx>, &'tcx List<Ty<'tcx>>>,
{
self.mk_type_list_from_iter(args)
}
@ -312,6 +326,24 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.item_bounds(def_id).map_bound(IntoIterator::into_iter)
}
fn predicates_of(
self,
def_id: DefId,
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
ty::EarlyBinder::bind(
self.predicates_of(def_id).instantiate_identity(self).predicates.into_iter(),
)
}
fn own_predicates_of(
self,
def_id: DefId,
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
ty::EarlyBinder::bind(
self.predicates_of(def_id).instantiate_own_identity().map(|(clause, _)| clause),
)
}
fn super_predicates_of(
self,
def_id: DefId,
@ -326,15 +358,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
}
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId {
self.require_lang_item(
match lang_item {
TraitSolverLangItem::Future => hir::LangItem::Future,
TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput,
TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper,
TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars,
},
None,
)
self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None)
}
fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool {
self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item))
}
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
@ -343,6 +371,257 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
.filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
.map(|assoc_item| assoc_item.def_id)
}
fn args_may_unify_deep(
self,
obligation_args: ty::GenericArgsRef<'tcx>,
impl_args: ty::GenericArgsRef<'tcx>,
) -> bool {
ty::fast_reject::DeepRejectCtxt {
treat_obligation_params: ty::fast_reject::TreatParams::ForLookup,
}
.args_may_unify(obligation_args, impl_args)
}
// This implementation is a bit different from `TyCtxt::for_each_relevant_impl`,
// since we want to skip over blanket impls for non-rigid aliases, and also we
// only want to consider types that *actually* unify with float/int vars.
fn for_each_relevant_impl(
self,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
mut f: impl FnMut(DefId),
) {
let tcx = self;
let trait_impls = tcx.trait_impls_of(trait_def_id);
let mut consider_impls_for_simplified_type = |simp| {
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
for &impl_def_id in impls_for_type {
f(impl_def_id);
}
}
};
match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Adt(_, _)
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)
| ty::Never
| ty::Tuple(_) => {
let simp = ty::fast_reject::simplify_type(
tcx,
self_ty,
ty::fast_reject::TreatParams::ForLookup,
)
.unwrap();
consider_impls_for_simplified_type(simp);
}
// HACK: For integer and float variables we have to manually look at all impls
// which have some integer or float as a self type.
ty::Infer(ty::IntVar(_)) => {
use ty::IntTy::*;
use ty::UintTy::*;
// This causes a compiler error if any new integer kinds are added.
let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
let possible_integers = [
// signed integers
ty::SimplifiedType::Int(I8),
ty::SimplifiedType::Int(I16),
ty::SimplifiedType::Int(I32),
ty::SimplifiedType::Int(I64),
ty::SimplifiedType::Int(I128),
ty::SimplifiedType::Int(Isize),
// unsigned integers
ty::SimplifiedType::Uint(U8),
ty::SimplifiedType::Uint(U16),
ty::SimplifiedType::Uint(U32),
ty::SimplifiedType::Uint(U64),
ty::SimplifiedType::Uint(U128),
ty::SimplifiedType::Uint(Usize),
];
for simp in possible_integers {
consider_impls_for_simplified_type(simp);
}
}
ty::Infer(ty::FloatVar(_)) => {
// This causes a compiler error if any new float kinds are added.
let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128);
let possible_floats = [
ty::SimplifiedType::Float(ty::FloatTy::F16),
ty::SimplifiedType::Float(ty::FloatTy::F32),
ty::SimplifiedType::Float(ty::FloatTy::F64),
ty::SimplifiedType::Float(ty::FloatTy::F128),
];
for simp in possible_floats {
consider_impls_for_simplified_type(simp);
}
}
// The only traits applying to aliases and placeholders are blanket impls.
//
// Impls which apply to an alias after normalization are handled by
// `assemble_candidates_after_normalizing_self_ty`.
ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
// FIXME: These should ideally not exist as a self type. It would be nice for
// the builtin auto trait impls of coroutines to instead directly recurse
// into the witness.
ty::CoroutineWitness(..) => (),
// These variants should not exist as a self type.
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Param(_)
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
}
let trait_impls = tcx.trait_impls_of(trait_def_id);
for &impl_def_id in trait_impls.blanket_impls() {
f(impl_def_id);
}
}
fn has_item_definition(self, def_id: DefId) -> bool {
self.defaultness(def_id).has_value()
}
fn impl_is_default(self, impl_def_id: DefId) -> bool {
self.defaultness(impl_def_id).is_default()
}
fn impl_trait_ref(self, impl_def_id: DefId) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> {
self.impl_trait_ref(impl_def_id).unwrap()
}
fn impl_polarity(self, impl_def_id: DefId) -> ty::ImplPolarity {
self.impl_polarity(impl_def_id)
}
fn trait_is_auto(self, trait_def_id: DefId) -> bool {
self.trait_is_auto(trait_def_id)
}
fn trait_is_alias(self, trait_def_id: DefId) -> bool {
self.trait_is_alias(trait_def_id)
}
fn trait_is_object_safe(self, trait_def_id: DefId) -> bool {
self.is_object_safe(trait_def_id)
}
fn trait_may_be_implemented_via_object(self, trait_def_id: DefId) -> bool {
self.trait_def(trait_def_id).implement_via_object
}
fn fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option<ty::ClosureKind> {
self.fn_trait_kind_from_def_id(trait_def_id)
}
fn async_fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option<ty::ClosureKind> {
self.async_fn_trait_kind_from_def_id(trait_def_id)
}
fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator<Item = DefId> {
self.supertrait_def_ids(trait_def_id)
}
fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed {
self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string())
}
fn is_general_coroutine(self, coroutine_def_id: DefId) -> bool {
self.is_general_coroutine(coroutine_def_id)
}
fn coroutine_is_async(self, coroutine_def_id: DefId) -> bool {
self.coroutine_is_async(coroutine_def_id)
}
fn coroutine_is_gen(self, coroutine_def_id: DefId) -> bool {
self.coroutine_is_gen(coroutine_def_id)
}
fn coroutine_is_async_gen(self, coroutine_def_id: DefId) -> bool {
self.coroutine_is_async_gen(coroutine_def_id)
}
fn layout_is_pointer_like(self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
self.layout_of(self.erase_regions(param_env.and(ty)))
.is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout))
}
type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>;
fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
self.unsizing_params_for_adt(adt_def_id)
}
fn find_const_ty_from_env(
self,
param_env: ty::ParamEnv<'tcx>,
placeholder: Self::PlaceholderConst,
) -> Ty<'tcx> {
placeholder.find_const_ty_from_env(param_env)
}
}
fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem {
match lang_item {
TraitSolverLangItem::AsyncDestruct => LangItem::AsyncDestruct,
TraitSolverLangItem::AsyncFnKindHelper => LangItem::AsyncFnKindHelper,
TraitSolverLangItem::AsyncFnKindUpvars => LangItem::AsyncFnKindUpvars,
TraitSolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput,
TraitSolverLangItem::AsyncIterator => LangItem::AsyncIterator,
TraitSolverLangItem::CallOnceFuture => LangItem::CallOnceFuture,
TraitSolverLangItem::CallRefFuture => LangItem::CallRefFuture,
TraitSolverLangItem::Clone => LangItem::Clone,
TraitSolverLangItem::Copy => LangItem::Copy,
TraitSolverLangItem::Coroutine => LangItem::Coroutine,
TraitSolverLangItem::CoroutineReturn => LangItem::CoroutineReturn,
TraitSolverLangItem::CoroutineYield => LangItem::CoroutineYield,
TraitSolverLangItem::Destruct => LangItem::Destruct,
TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind,
TraitSolverLangItem::DynMetadata => LangItem::DynMetadata,
TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait,
TraitSolverLangItem::FusedIterator => LangItem::FusedIterator,
TraitSolverLangItem::Future => LangItem::Future,
TraitSolverLangItem::FutureOutput => LangItem::FutureOutput,
TraitSolverLangItem::Iterator => LangItem::Iterator,
TraitSolverLangItem::Metadata => LangItem::Metadata,
TraitSolverLangItem::Option => LangItem::Option,
TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait,
TraitSolverLangItem::PointerLike => LangItem::PointerLike,
TraitSolverLangItem::Poll => LangItem::Poll,
TraitSolverLangItem::Sized => LangItem::Sized,
TraitSolverLangItem::TransmuteTrait => LangItem::TransmuteTrait,
TraitSolverLangItem::Tuple => LangItem::Tuple,
TraitSolverLangItem::Unpin => LangItem::Unpin,
TraitSolverLangItem::Unsize => LangItem::Unsize,
}
}
impl<'tcx> rustc_type_ir::inherent::DefId<TyCtxt<'tcx>> for DefId {
fn as_local(self) -> Option<LocalDefId> {
self.as_local()
}
}
impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
@ -377,6 +656,10 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
fn coroutine_clone(self) -> bool {
self.coroutine_clone
}
fn associated_const_equality(self) -> bool {
self.associated_const_equality
}
}
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;

View File

@ -44,10 +44,23 @@ pub struct GenericArg<'tcx> {
impl<'tcx> rustc_type_ir::inherent::GenericArg<TyCtxt<'tcx>> for GenericArg<'tcx> {}
impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
fn rebase_onto(
self,
tcx: TyCtxt<'tcx>,
source_ancestor: DefId,
target_args: GenericArgsRef<'tcx>,
) -> GenericArgsRef<'tcx> {
self.rebase_onto(tcx, source_ancestor, target_args)
}
fn type_at(self, i: usize) -> Ty<'tcx> {
self.type_at(i)
}
fn region_at(self, i: usize) -> ty::Region<'tcx> {
self.region_at(i)
}
fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
GenericArgs::identity_for_item(tcx, def_id)
}
@ -281,6 +294,7 @@ impl<'tcx> GenericArg<'tcx> {
pub fn is_non_region_infer(self) -> bool {
match self.unpack() {
GenericArgKind::Lifetime(_) => false,
// FIXME: This shouldn't return numerical/float.
GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(),
GenericArgKind::Const(ct) => ct.is_ct_infer(),
}

View File

@ -392,6 +392,10 @@ impl<'tcx> GenericPredicates<'tcx> {
EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
}
pub fn instantiate_own_identity(&self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
EarlyBinder::bind(self.predicates).instantiate_identity_iter_copied()
}
#[instrument(level = "debug", skip(self, tcx))]
fn instantiate_into(
&self,

View File

@ -990,6 +990,16 @@ pub struct ParamEnv<'tcx> {
packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>,
}
impl<'tcx> rustc_type_ir::inherent::ParamEnv<TyCtxt<'tcx>> for ParamEnv<'tcx> {
fn reveal(self) -> Reveal {
self.reveal()
}
fn caller_bounds(self) -> impl IntoIterator<Item = ty::Clause<'tcx>> {
self.caller_bounds()
}
}
#[derive(Copy, Clone)]
struct ParamTag {
reveal: traits::Reveal,

View File

@ -175,6 +175,14 @@ pub struct Clause<'tcx>(
impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {}
impl<'tcx> rustc_type_ir::inherent::IntoKind for Clause<'tcx> {
type Kind = ty::Binder<'tcx, ClauseKind<'tcx>>;
fn kind(self) -> Self::Kind {
self.kind()
}
}
impl<'tcx> Clause<'tcx> {
pub fn as_predicate(self) -> Predicate<'tcx> {
Predicate(self.0)
@ -251,6 +259,28 @@ impl<'tcx> ExistentialPredicate<'tcx> {
pub type PolyExistentialPredicate<'tcx> = ty::Binder<'tcx, ExistentialPredicate<'tcx>>;
impl<'tcx> rustc_type_ir::inherent::BoundExistentialPredicates<TyCtxt<'tcx>>
for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>
{
fn principal_def_id(self) -> Option<DefId> {
self.principal_def_id()
}
fn principal(self) -> Option<ty::PolyExistentialTraitRef<'tcx>> {
self.principal()
}
fn auto_traits(self) -> impl IntoIterator<Item = DefId> {
self.auto_traits()
}
fn projection_bounds(
self,
) -> impl IntoIterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> {
self.projection_bounds()
}
}
impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
/// Returns the "principal `DefId`" of this set of existential predicates.
///
@ -481,12 +511,6 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Predicate<'tcx> {
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for TraitPredicate<'tcx> {
fn upcast_from(from: TraitRef<'tcx>, _tcx: TyCtxt<'tcx>) -> Self {
TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive }
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Clause<'tcx> {
fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
let p: Predicate<'tcx> = from.upcast(tcx);
@ -543,6 +567,12 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyTraitPredicate<'tcx>> for Clause<'tcx> {
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, RegionOutlivesPredicate<'tcx>> for Predicate<'tcx> {
fn upcast_from(from: RegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
ty::Binder::dummy(PredicateKind::Clause(ClauseKind::RegionOutlives(from))).upcast(tcx)
}
}
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyRegionOutlivesPredicate<'tcx>> for Predicate<'tcx> {
fn upcast_from(from: PolyRegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
from.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).upcast(tcx)

View File

@ -930,6 +930,22 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self {
Ty::new_pat(interner, ty, pat)
}
fn new_unit(interner: TyCtxt<'tcx>) -> Self {
interner.types.unit
}
fn new_usize(interner: TyCtxt<'tcx>) -> Self {
interner.types.usize
}
fn discriminant_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
self.discriminant_ty(interner)
}
fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
self.async_destructor_ty(interner)
}
}
/// Type utilities

View File

@ -565,42 +565,6 @@ impl<'tcx> TyCtxt<'tcx> {
Ok(())
}
/// Checks whether each generic argument is simply a unique generic placeholder.
///
/// This is used in the new solver, which canonicalizes params to placeholders
/// for better caching.
pub fn uses_unique_placeholders_ignoring_regions(
self,
args: GenericArgsRef<'tcx>,
) -> Result<(), NotUniqueParam<'tcx>> {
let mut seen = GrowableBitSet::default();
for arg in args {
match arg.unpack() {
// Ignore regions, since we can't resolve those in a canonicalized
// query in the trait solver.
GenericArgKind::Lifetime(_) => {}
GenericArgKind::Type(t) => match t.kind() {
ty::Placeholder(p) => {
if !seen.insert(p.bound.var) {
return Err(NotUniqueParam::DuplicateParam(t.into()));
}
}
_ => return Err(NotUniqueParam::NotParam(t.into())),
},
GenericArgKind::Const(c) => match c.kind() {
ty::ConstKind::Placeholder(p) => {
if !seen.insert(p.bound) {
return Err(NotUniqueParam::DuplicateParam(c.into()));
}
}
_ => return Err(NotUniqueParam::NotParam(c.into())),
},
}
}
Ok(())
}
/// Returns `true` if `def_id` refers to a closure, coroutine, or coroutine-closure
/// (i.e. an async closure). These are all represented by `hir::Closure`, and all
/// have the same `DefKind`.

View File

@ -5,9 +5,25 @@ edition = "2021"
[dependencies]
# tidy-alphabetical-start
bitflags = "2.4.1"
derivative = "2.2.0"
rustc_ast_ir = { path = "../rustc_ast_ir" }
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
rustc_index = { path = "../rustc_index", default-features = false }
rustc_macros = { path = "../rustc_macros", optional = true }
rustc_serialize = { path = "../rustc_serialize", optional = true }
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
tracing = "0.1"
# tidy-alphabetical-end
[features]
default = ["nightly"]
nightly = ["rustc_type_ir/nightly"]
nightly = [
"rustc_ast_ir/nightly",
"rustc_data_structures",
"rustc_index/nightly",
"rustc_macros",
"rustc_serialize",
"rustc_type_ir/nightly",
]

View File

@ -1,13 +1,27 @@
use std::fmt::Debug;
use rustc_type_ir::fold::TypeFoldable;
use rustc_type_ir::relate::Relate;
use rustc_type_ir::solve::{Goal, NoSolution};
use rustc_type_ir::solve::{Goal, NoSolution, SolverMode};
use rustc_type_ir::{self as ty, Interner};
pub trait SolverDelegate: Sized {
type Interner: Interner;
fn interner(&self) -> Self::Interner;
fn solver_mode(&self) -> SolverMode;
fn build_with_canonical<V>(
interner: Self::Interner,
solver_mode: SolverMode,
canonical: &ty::Canonical<Self::Interner, V>,
) -> (Self, V, ty::CanonicalVarValues<Self::Interner>)
where
V: TypeFoldable<Self::Interner>;
fn universe(&self) -> ty::UniverseIndex;
fn create_next_universe(&self) -> ty::UniverseIndex;
fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
@ -74,4 +88,102 @@ pub trait SolverDelegate: Sized {
T: TypeFoldable<Self::Interner>;
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
// FIXME: Uplift the leak check into this crate.
fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>;
// FIXME: This is only here because elaboration lives in `rustc_infer`!
fn elaborate_supertraits(
interner: Self::Interner,
trait_ref: ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>,
) -> impl Iterator<Item = ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>>;
fn try_const_eval_resolve(
&self,
param_env: <Self::Interner as Interner>::ParamEnv,
unevaluated: ty::UnevaluatedConst<Self::Interner>,
) -> Option<<Self::Interner as Interner>::Const>;
fn sub_regions(
&self,
sub: <Self::Interner as Interner>::Region,
sup: <Self::Interner as Interner>::Region,
);
fn register_ty_outlives(
&self,
ty: <Self::Interner as Interner>::Ty,
r: <Self::Interner as Interner>::Region,
);
// FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`!
fn well_formed_goals(
&self,
param_env: <Self::Interner as Interner>::ParamEnv,
arg: <Self::Interner as Interner>::GenericArg,
) -> Option<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>>;
fn clone_opaque_types_for_query_response(
&self,
) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
fn make_deduplicated_outlives_constraints(
&self,
) -> Vec<ty::OutlivesPredicate<Self::Interner, <Self::Interner as Interner>::GenericArg>>;
fn instantiate_canonical<V>(
&self,
canonical: ty::Canonical<Self::Interner, V>,
values: ty::CanonicalVarValues<Self::Interner>,
) -> V
where
V: TypeFoldable<Self::Interner>;
fn instantiate_canonical_var_with_infer(
&self,
cv_info: ty::CanonicalVarInfo<Self::Interner>,
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
) -> <Self::Interner as Interner>::GenericArg;
// FIXME: Can we implement this in terms of `add` and `inject`?
fn insert_hidden_type(
&self,
opaque_type_key: ty::OpaqueTypeKey<Self::Interner>,
param_env: <Self::Interner as Interner>::ParamEnv,
hidden_ty: <Self::Interner as Interner>::Ty,
goals: &mut Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
) -> Result<(), NoSolution>;
fn add_item_bounds_for_hidden_type(
&self,
def_id: <Self::Interner as Interner>::DefId,
args: <Self::Interner as Interner>::GenericArgs,
param_env: <Self::Interner as Interner>::ParamEnv,
hidden_ty: <Self::Interner as Interner>::Ty,
goals: &mut Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
);
fn inject_new_hidden_type_unchecked(
&self,
key: ty::OpaqueTypeKey<Self::Interner>,
hidden_ty: <Self::Interner as Interner>::Ty,
);
fn reset_opaque_types(&self);
fn trait_ref_is_knowable<E: Debug>(
&self,
trait_ref: ty::TraitRef<Self::Interner>,
lazily_normalize_ty: impl FnMut(
<Self::Interner as Interner>::Ty,
) -> Result<<Self::Interner as Interner>::Ty, E>,
) -> Result<bool, E>;
fn fetch_eligible_assoc_item(
&self,
param_env: <Self::Interner as Interner>::ParamEnv,
goal_trait_ref: ty::TraitRef<Self::Interner>,
trait_assoc_def_id: <Self::Interner as Interner>::DefId,
impl_def_id: <Self::Interner as Interner>::DefId,
) -> Result<Option<<Self::Interner as Interner>::DefId>, NoSolution>;
}

View File

@ -4,6 +4,12 @@
//! but were uplifted in the process of making the new trait solver generic.
//! So if you got to this crate from the old solver, it's totally normal.
#![feature(let_chains)]
// TODO: remove this, use explicit imports.
#[macro_use]
extern crate tracing;
pub mod canonicalizer;
pub mod infcx;
pub mod resolve;

View File

@ -1 +0,0 @@
pub use rustc_type_ir::solve::*;

View File

@ -15,17 +15,22 @@
//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! relate them structurally.
use super::infcx::SolverDelegate;
use super::EvalCtxt;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty;
use rustc_type_ir::inherent::*;
use rustc_type_ir::{self as ty, Interner};
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
use crate::infcx::SolverDelegate;
use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult};
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "trace", skip(self), ret)]
pub(super) fn compute_alias_relate_goal(
&mut self,
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
) -> QueryResult<'tcx> {
goal: Goal<I, (I::Term, I::Term, ty::AliasRelationDirection)>,
) -> QueryResult<I> {
let tcx = self.interner();
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some());

View File

@ -1,33 +1,25 @@
//! Code shared by trait and projection goals for candidate assembly.
use crate::solve::infcx::SolverDelegate;
use derivative::Derivative;
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::supertraits;
use rustc_middle::bug;
use rustc_middle::traits::solve::inspect::ProbeKind;
use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause, QueryResult};
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{fast_reject, TypeFoldable};
use rustc_middle::ty::{TypeVisitableExt, Upcast};
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
use rustc_type_ir::solve::{CandidateSource, CanonicalResponse};
use rustc_type_ir::Interner;
use crate::solve::GoalSource;
use crate::solve::{EvalCtxt, SolverMode};
pub(super) mod structural_traits;
use rustc_type_ir::fold::TypeFoldable;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::visit::TypeVisitableExt as _;
use rustc_type_ir::{self as ty, Interner, Upcast as _};
use crate::infcx::SolverDelegate;
use crate::solve::inspect::ProbeKind;
use crate::solve::{
BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
MaybeCause, NoSolution, QueryResult, SolverMode,
};
/// A candidate is a possible way to prove a goal.
///
/// It consists of both the `source`, which describes how that goal would be proven,
/// and the `result` when using the given `source`.
#[derive(Derivative)]
#[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))]
pub(super) struct Candidate<I: Interner> {
pub(super) source: CandidateSource<I>,
@ -35,39 +27,42 @@ pub(super) struct Candidate<I: Interner> {
}
/// Methods used to assemble candidates for either trait or projection goals.
pub(super) trait GoalKind<'tcx>:
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
pub(super) trait GoalKind<Infcx, I = <Infcx as SolverDelegate>::Interner>:
TypeFoldable<I> + Copy + Eq + std::fmt::Display
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
fn self_ty(self) -> Ty<'tcx>;
fn self_ty(self) -> I::Ty;
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
fn trait_ref(self, tcx: I) -> ty::TraitRef<I>;
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self;
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
fn trait_def_id(self, tcx: I) -> I::DefId;
/// Try equating an assumption predicate against a goal's predicate. If it
/// holds, then execute the `then` callback, which should do any additional
/// work, then produce a response (typically by executing
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
source: CandidateSource<TyCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
then: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>) -> QueryResult<'tcx>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
source: CandidateSource<I>,
goal: Goal<I, Self>,
assumption: I::Clause,
then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
) -> Result<Candidate<I>, NoSolution>;
/// Consider a clause, which consists of a "assumption" and some "requirements",
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
/// goal by equating it with the assumption.
fn probe_and_consider_implied_clause(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
parent_source: CandidateSource<TyCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
parent_source: CandidateSource<I>,
goal: Goal<I, Self>,
assumption: I::Clause,
requirements: impl IntoIterator<Item = (GoalSource, Goal<I, I::Predicate>)>,
) -> Result<Candidate<I>, NoSolution> {
Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| {
for (nested_source, goal) in requirements {
ecx.add_goal(nested_source, goal);
@ -80,15 +75,15 @@ pub(super) trait GoalKind<'tcx>:
/// additionally checking all of the supertraits and object bounds to hold,
/// since they're not implied by the well-formedness of the object type.
fn probe_and_consider_object_bound_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
source: CandidateSource<TyCtxt<'tcx>>,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
source: CandidateSource<I>,
goal: Goal<I, Self>,
assumption: I::Clause,
) -> Result<Candidate<I>, NoSolution> {
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
let tcx = ecx.interner();
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
bug!("expected object type in `probe_and_consider_object_bound_candidate`");
let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {
panic!("expected object type in `probe_and_consider_object_bound_candidate`");
};
ecx.add_goals(
GoalSource::ImplWhereBound,
@ -104,10 +99,10 @@ pub(super) trait GoalKind<'tcx>:
}
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
impl_def_id: DefId,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
impl_def_id: I::DefId,
) -> Result<Candidate<I>, NoSolution>;
/// If the predicate contained an error, we want to avoid emitting unnecessary trait
/// errors but still want to emit errors for other trait goals. We have some special
@ -116,85 +111,85 @@ pub(super) trait GoalKind<'tcx>:
/// Trait goals always hold while projection goals never do. This is a bit arbitrary
/// but prevents incorrect normalization while hiding any trait errors.
fn consider_error_guaranteed_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
guar: ErrorGuaranteed,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
guar: I::ErrorGuaranteed,
) -> Result<Candidate<I>, NoSolution>;
/// A type implements an `auto trait` if its components do as well.
///
/// These components are given by built-in rules from
/// [`structural_traits::instantiate_constituent_tys_for_auto_trait`].
fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A trait alias holds if the RHS traits and `where` clauses hold.
fn consider_trait_alias_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A type is `Sized` if its tail component is `Sized`.
///
/// These components are given by built-in rules from
/// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
fn consider_builtin_sized_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
///
/// These components are given by built-in rules from
/// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`].
fn consider_builtin_copy_clone_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A type is `PointerLike` if we can compute its layout, and that layout
/// matches the layout of `usize`.
fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A type is a `FnPtr` if it is of `FnPtr` type.
fn consider_builtin_fn_ptr_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
/// family of traits where `A` is given by the signature of the type.
fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
) -> Result<Candidate<I>, NoSolution>;
/// An async closure is known to implement the `AsyncFn<A>` family of traits
/// where `A` is given by the signature of the type.
fn consider_builtin_async_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
) -> Result<Candidate<I>, NoSolution>;
/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
/// is used internally to delay computation for async closures until after
/// upvar analysis is performed in HIR typeck.
fn consider_builtin_async_fn_kind_helper_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// `Tuple` is implemented if the `Self` type is a tuple.
fn consider_builtin_tuple_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// `Pointee` is always implemented.
///
@ -202,65 +197,65 @@ pub(super) trait GoalKind<'tcx>:
/// the built-in types. For structs, the metadata type is given by the struct
/// tail.
fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A coroutine (that comes from an `async` desugaring) is known to implement
/// `Future<Output = O>`, where `O` is given by the coroutine's return type
/// that was computed during type-checking.
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A coroutine (that comes from a `gen` desugaring) is known to implement
/// `Iterator<Item = O>`, where `O` is given by the generator's yield type
/// that was computed during type-checking.
fn consider_builtin_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A coroutine (that comes from a `gen` desugaring) is known to implement
/// `FusedIterator`
fn consider_builtin_fused_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_async_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
/// and return types of the coroutine computed during type-checking.
fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_async_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_transmute_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution>;
/// Consider (possibly several) candidates to upcast or unsize a type to another
/// type, excluding the coercion of a sized type into a `dyn Trait`.
@ -270,16 +265,20 @@ pub(super) trait GoalKind<'tcx>:
/// 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_structural_builtin_unsize_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Vec<Candidate<TyCtxt<'tcx>>>;
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Vec<Candidate<I>>;
}
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<Infcx>>(
&mut self,
goal: Goal<'tcx, G>,
) -> Vec<Candidate<TyCtxt<'tcx>>> {
goal: Goal<I, G>,
) -> Vec<Candidate<I>> {
let Ok(normalized_self_ty) =
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
else {
@ -291,7 +290,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
}
let goal: Goal<'tcx, G> = goal.with(
let goal: Goal<I, G> = goal.with(
self.interner(),
goal.predicate.with_self_ty(self.interner(), normalized_self_ty),
);
@ -301,7 +300,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
let mut candidates = vec![];
self.assemble_non_blanket_impl_candidates(goal, &mut candidates);
self.assemble_impl_candidates(goal, &mut candidates);
self.assemble_builtin_impl_candidates(goal, &mut candidates);
@ -309,8 +308,6 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
self.assemble_object_bound_candidates(goal, &mut candidates);
self.assemble_blanket_impl_candidates(goal, &mut candidates);
self.assemble_param_env_candidates(goal, &mut candidates);
match self.solver_mode() {
@ -326,7 +323,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
pub(super) fn forced_ambiguity(
&mut self,
cause: MaybeCause,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
) -> Result<Candidate<I>, NoSolution> {
// This may fail if `try_evaluate_added_goals` overflows because it
// fails to reach a fixpoint but ends up getting an error after
// running for some additional step.
@ -339,21 +336,20 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
}
#[instrument(level = "trace", skip_all)]
fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>(
fn assemble_impl_candidates<G: GoalKind<Infcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
goal: Goal<I, G>,
candidates: &mut Vec<Candidate<I>>,
) {
let tcx = self.interner();
let self_ty = goal.predicate.self_ty();
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
let mut consider_impls_for_simplified_type = |simp| {
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
for &impl_def_id in impls_for_type {
tcx.for_each_relevant_impl(
goal.predicate.trait_def_id(tcx),
goal.predicate.self_ty(),
|impl_def_id| {
// For every `default impl`, there's always a non-default `impl`
// that will *also* apply. There's no reason to register a candidate
// for this impl, since it is *not* proof that the trait goal holds.
if tcx.defaultness(impl_def_id).is_default() {
if tcx.impl_is_default(impl_def_id) {
return;
}
@ -361,127 +357,15 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (),
}
}
}
};
match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Adt(_, _)
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(_, _)
| ty::Never
| ty::Tuple(_) => {
let simp =
fast_reject::simplify_type(tcx, self_ty, TreatParams::ForLookup).unwrap();
consider_impls_for_simplified_type(simp);
}
// HACK: For integer and float variables we have to manually look at all impls
// which have some integer or float as a self type.
ty::Infer(ty::IntVar(_)) => {
use ty::IntTy::*;
use ty::UintTy::*;
// This causes a compiler error if any new integer kinds are added.
let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
let possible_integers = [
// signed integers
SimplifiedType::Int(I8),
SimplifiedType::Int(I16),
SimplifiedType::Int(I32),
SimplifiedType::Int(I64),
SimplifiedType::Int(I128),
SimplifiedType::Int(Isize),
// unsigned integers
SimplifiedType::Uint(U8),
SimplifiedType::Uint(U16),
SimplifiedType::Uint(U32),
SimplifiedType::Uint(U64),
SimplifiedType::Uint(U128),
SimplifiedType::Uint(Usize),
];
for simp in possible_integers {
consider_impls_for_simplified_type(simp);
}
}
ty::Infer(ty::FloatVar(_)) => {
// This causes a compiler error if any new float kinds are added.
let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128);
let possible_floats = [
SimplifiedType::Float(ty::FloatTy::F16),
SimplifiedType::Float(ty::FloatTy::F32),
SimplifiedType::Float(ty::FloatTy::F64),
SimplifiedType::Float(ty::FloatTy::F128),
];
for simp in possible_floats {
consider_impls_for_simplified_type(simp);
}
}
// The only traits applying to aliases and placeholders are blanket impls.
//
// Impls which apply to an alias after normalization are handled by
// `assemble_candidates_after_normalizing_self_ty`.
ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
// FIXME: These should ideally not exist as a self type. It would be nice for
// the builtin auto trait impls of coroutines to instead directly recurse
// into the witness.
ty::CoroutineWitness(..) => (),
// These variants should not exist as a self type.
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Param(_)
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
}
},
);
}
#[instrument(level = "trace", skip_all)]
fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>(
fn assemble_builtin_impl_candidates<G: GoalKind<Infcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
) {
let tcx = self.interner();
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
for &impl_def_id in trait_impls.blanket_impls() {
// For every `default impl`, there's always a non-default `impl`
// that will *also* apply. There's no reason to register a candidate
// for this impl, since it is *not* proof that the trait goal holds.
if tcx.defaultness(impl_def_id).is_default() {
return;
}
match G::consider_impl_candidate(self, goal, impl_def_id) {
Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (),
}
}
}
#[instrument(level = "trace", skip_all)]
fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
goal: Goal<I, G>,
candidates: &mut Vec<Candidate<I>>,
) {
let tcx = self.interner();
let trait_def_id = goal.predicate.trait_def_id(tcx);
@ -499,43 +383,43 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
G::consider_auto_trait_candidate(self, goal)
} else if tcx.trait_is_alias(trait_def_id) {
G::consider_trait_alias_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::Sized) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) {
G::consider_builtin_sized_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::Copy)
|| tcx.is_lang_item(trait_def_id, LangItem::Clone)
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy)
|| tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone)
{
G::consider_builtin_copy_clone_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::PointerLike) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) {
G::consider_builtin_pointer_like_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::FnPtrTrait) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) {
G::consider_builtin_fn_ptr_trait_candidate(self, goal)
} else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) {
G::consider_builtin_fn_trait_candidates(self, goal, kind)
} else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) {
G::consider_builtin_async_fn_trait_candidates(self, goal, kind)
} else if tcx.is_lang_item(trait_def_id, LangItem::AsyncFnKindHelper) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) {
G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::Tuple) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) {
G::consider_builtin_tuple_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) {
G::consider_builtin_pointee_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::Future) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) {
G::consider_builtin_future_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::Iterator) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) {
G::consider_builtin_iterator_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::FusedIterator) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) {
G::consider_builtin_fused_iterator_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::AsyncIterator) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) {
G::consider_builtin_async_iterator_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) {
G::consider_builtin_coroutine_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) {
G::consider_builtin_discriminant_kind_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) {
G::consider_builtin_async_destruct_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::Destruct) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) {
G::consider_builtin_destruct_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::TransmuteTrait) {
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) {
G::consider_builtin_transmute_candidate(self, goal)
} else {
Err(NoSolution)
@ -545,18 +429,18 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// There may be multiple unsize candidates for a trait with several supertraits:
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
if tcx.is_lang_item(trait_def_id, LangItem::Unsize) {
if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) {
candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
}
}
#[instrument(level = "trace", skip_all)]
fn assemble_param_env_candidates<G: GoalKind<'tcx>>(
fn assemble_param_env_candidates<G: GoalKind<Infcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
goal: Goal<I, G>,
candidates: &mut Vec<Candidate<I>>,
) {
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
for (i, assumption) in goal.param_env.caller_bounds().into_iter().enumerate() {
candidates.extend(G::probe_and_consider_implied_clause(
self,
CandidateSource::ParamEnv(i),
@ -568,10 +452,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
}
#[instrument(level = "trace", skip_all)]
fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
fn assemble_alias_bound_candidates<G: GoalKind<Infcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
goal: Goal<I, G>,
candidates: &mut Vec<Candidate<I>>,
) {
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
@ -587,13 +471,13 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// If so, continue searching by recursively calling after normalization.
// FIXME: This may recurse infinitely, but I can't seem to trigger it without
// hitting another overflow error something. Add a depth parameter needed later.
fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
fn assemble_alias_bound_candidates_recur<G: GoalKind<Infcx>>(
&mut self,
self_ty: Ty<'tcx>,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
self_ty: I::Ty,
goal: Goal<I, G>,
candidates: &mut Vec<Candidate<I>>,
) {
let (kind, alias_ty) = match *self_ty.kind() {
let (kind, alias_ty) = match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@ -621,7 +505,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Error(_) => return,
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
bug!("unexpected self type for `{goal:?}`")
panic!("unexpected self type for `{goal:?}`")
}
ty::Infer(ty::TyVar(_)) => {
@ -638,16 +522,15 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
ty::Alias(ty::Inherent | ty::Weak, _) => {
self.interner().sess.dcx().span_delayed_bug(
DUMMY_SP,
format!("could not normalize {self_ty}, it is not WF"),
);
self.interner().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
return;
}
};
for assumption in
self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args)
for assumption in self
.interner()
.item_bounds(alias_ty.def_id)
.iter_instantiated(self.interner(), &alias_ty.args)
{
candidates.extend(G::probe_and_consider_implied_clause(
self,
@ -672,18 +555,18 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
}
#[instrument(level = "trace", skip_all)]
fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
fn assemble_object_bound_candidates<G: GoalKind<Infcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
goal: Goal<I, G>,
candidates: &mut Vec<Candidate<I>>,
) {
let tcx = self.interner();
if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object {
if !tcx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(tcx)) {
return;
}
let self_ty = goal.predicate.self_ty();
let bounds = match *self_ty.kind() {
let bounds = match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@ -711,12 +594,12 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Error(_) => return,
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
| ty::Bound(..) => panic!("unexpected self type for `{goal:?}`"),
ty::Dynamic(bounds, ..) => bounds,
};
// Do not consider built-in object impls for non-object-safe types.
if bounds.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) {
if bounds.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) {
return;
}
@ -745,7 +628,9 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// a projection goal.
if let Some(principal) = bounds.principal() {
let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
for (idx, assumption) in supertraits(self.interner(), principal_trait_ref).enumerate() {
for (idx, assumption) in
Infcx::elaborate_supertraits(tcx, principal_trait_ref).enumerate()
{
candidates.extend(G::probe_and_consider_object_bound_candidate(
self,
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
@ -763,10 +648,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// To do so we add an ambiguous candidate in case such an unknown impl could
/// apply to the current goal.
#[instrument(level = "trace", skip_all)]
fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>(
fn assemble_coherence_unknowable_candidates<G: GoalKind<Infcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
goal: Goal<I, G>,
candidates: &mut Vec<Candidate<I>>,
) {
let tcx = self.interner();
@ -792,13 +677,13 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// to improve this however. However, this should make it fairly straightforward to refine
// the filtering going forward, so it seems alright-ish for now.
#[instrument(level = "debug", skip(self, goal))]
fn discard_impls_shadowed_by_env<G: GoalKind<'tcx>>(
fn discard_impls_shadowed_by_env<G: GoalKind<Infcx>>(
&mut self,
goal: Goal<'tcx, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
goal: Goal<I, G>,
candidates: &mut Vec<Candidate<I>>,
) {
let tcx = self.interner();
let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
let trait_goal: Goal<I, ty::TraitPredicate<I>> =
goal.with(tcx, goal.predicate.trait_ref(tcx));
let mut trait_candidates_from_env = vec![];
@ -823,7 +708,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
false
}
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true,
CandidateSource::CoherenceUnknowable => bug!("uh oh"),
CandidateSource::CoherenceUnknowable => panic!("uh oh"),
});
}
// If it is still ambiguous we instead just force the whole goal
@ -841,10 +726,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// to somehow try to merge the candidates into one. If that fails, we return
/// ambiguity.
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_candidates(
&mut self,
candidates: Vec<Candidate<TyCtxt<'tcx>>>,
) -> QueryResult<'tcx> {
pub(super) fn merge_candidates(&mut self, candidates: Vec<Candidate<I>>) -> QueryResult<I> {
// First try merging all candidates. This is complete and fully sound.
let responses = candidates.iter().map(|c| c.result).collect::<Vec<_>>();
if let Some(result) = self.try_merge_responses(&responses) {

View File

@ -3,20 +3,16 @@
use rustc_ast_ir::{Movability, Mutability};
use rustc_data_structures::fx::FxHashMap;
use rustc_next_trait_solver::infcx::SolverDelegate;
use rustc_next_trait_solver::solve::{Goal, NoSolution};
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::{self as ty, Interner, Upcast};
use rustc_type_ir::{self as ty, Interner, Upcast as _};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use crate::solve::EvalCtxt;
use crate::infcx::SolverDelegate;
use crate::solve::{EvalCtxt, Goal, NoSolution};
// Calculates the constituent types of a type for `auto trait` purposes.
//
// For types with an "existential" binder, i.e. coroutine witnesses, we also
// instantiate the binder with placeholders eagerly.
#[instrument(level = "trace", skip(ecx), ret)]
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<Infcx, I>(
ecx: &EvalCtxt<'_, Infcx>,
@ -745,7 +741,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I>
)
.expect("expected to be able to unify goal projection with dyn's projection"),
);
proj.term.expect_type()
proj.term.expect_ty()
} else {
ty.super_fold_with(self)
}

View File

@ -8,60 +8,52 @@
//! section of the [rustc-dev-guide][c].
//!
//! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
use crate::solve::eval_ctxt::NestedGoals;
use crate::solve::infcx::SolverDelegate;
use crate::solve::{
inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response,
};
use rustc_data_structures::fx::FxHashSet;
use rustc_index::IndexVec;
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
use rustc_infer::infer::RegionVariableOrigin;
use rustc_infer::infer::{InferCtxt, InferOk};
use rustc_infer::traits::solve::NestedNormalizationGoals;
use rustc_middle::bug;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{
ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
use rustc_next_trait_solver::infcx::SolverDelegate as IrSolverDelegate;
use rustc_next_trait_solver::resolve::EagerResolver;
use rustc_span::{Span, DUMMY_SP};
use rustc_type_ir::CanonicalVarValues;
use rustc_type_ir::Interner;
use std::assert_matches::assert_matches;
use std::iter;
use std::ops::Deref;
trait ResponseT<'tcx> {
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>>;
use rustc_index::IndexVec;
use rustc_type_ir::fold::TypeFoldable;
use rustc_type_ir::inherent::*;
use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner};
use crate::canonicalizer::{CanonicalizeMode, Canonicalizer};
use crate::infcx::SolverDelegate;
use crate::resolve::EagerResolver;
use crate::solve::eval_ctxt::NestedGoals;
use crate::solve::inspect;
use crate::solve::{
response_no_constraints_raw, CanonicalInput, CanonicalResponse, Certainty, EvalCtxt,
ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution,
PredefinedOpaquesData, QueryInput, QueryResult, Response,
};
trait ResponseT<I: Interner> {
fn var_values(&self) -> CanonicalVarValues<I>;
}
impl<'tcx> ResponseT<'tcx> for Response<TyCtxt<'tcx>> {
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> {
impl<I: Interner> ResponseT<I> for Response<I> {
fn var_values(&self) -> CanonicalVarValues<I> {
self.var_values
}
}
impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> {
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> {
impl<I: Interner, T> ResponseT<I> for inspect::State<I, T> {
fn var_values(&self) -> CanonicalVarValues<I> {
self.var_values
}
}
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
/// Canonicalizes the goal remembering the original values
/// for each bound variable.
pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>(
pub(super) fn canonicalize_goal<T: TypeFoldable<I>>(
&self,
goal: Goal<'tcx, T>,
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
goal: Goal<I, T>,
) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) {
let opaque_types = self.infcx.clone_opaque_types_for_query_response();
let (goal, opaque_types) =
(goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx));
@ -91,7 +83,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
&mut self,
certainty: Certainty,
) -> QueryResult<'tcx> {
) -> QueryResult<I> {
self.inspect.make_canonical_response(certainty);
let goals_certainty = self.try_evaluate_added_goals()?;
@ -104,8 +96,8 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// We only check for leaks from universes which were entered inside
// of the query.
self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
trace!(?e, "failed the leak check");
self.infcx.leak_check(self.max_input_universe).map_err(|NoSolution| {
trace!("failed the leak check");
NoSolution
})?;
@ -121,7 +113,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
if cfg!(debug_assertions) {
assert!(normalizes_to_goals.is_empty());
if goals.is_empty() {
assert_matches!(goals_certainty, Certainty::Yes);
assert!(matches!(goals_certainty, Certainty::Yes));
}
}
(certainty, NestedNormalizationGoals(goals))
@ -160,7 +152,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
pub(in crate::solve) fn make_ambiguous_response_no_constraints(
&self,
maybe_cause: MaybeCause,
) -> CanonicalResponse<'tcx> {
) -> CanonicalResponse<I> {
response_no_constraints_raw(
self.interner(),
self.max_input_universe,
@ -180,8 +172,8 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
fn compute_external_query_constraints(
&self,
certainty: Certainty,
normalization_nested_goals: NestedNormalizationGoals<TyCtxt<'tcx>>,
) -> ExternalConstraintsData<TyCtxt<'tcx>> {
normalization_nested_goals: NestedNormalizationGoals<I>,
) -> ExternalConstraintsData<I> {
// We only return region constraints once the certainty is `Yes`. This
// is necessary as we may drop nested goals on ambiguity, which may result
// in unconstrained inference variables in the region constraints. It also
@ -191,26 +183,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and
// `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`.
let region_constraints = if certainty == Certainty::Yes {
// Cannot use `take_registered_region_obligations` as we may compute the response
// inside of a `probe` whenever we have multiple choices inside of the solver.
let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
let QueryRegionConstraints { outlives, member_constraints } =
self.infcx.with_region_constraints(|region_constraints| {
make_query_region_constraints(
self.interner(),
region_obligations.iter().map(|r_o| {
(r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())
}),
region_constraints,
)
});
assert_eq!(member_constraints, vec![]);
let mut seen = FxHashSet::default();
outlives
.into_iter()
.filter(|(outlives, _)| seen.insert(*outlives))
.map(|(outlives, _origin)| outlives)
.collect()
self.infcx.make_deduplicated_outlives_constraints()
} else {
Default::default()
};
@ -240,10 +213,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// the `normalization_nested_goals`
pub(super) fn instantiate_and_apply_query_response(
&mut self,
param_env: ty::ParamEnv<'tcx>,
original_values: Vec<ty::GenericArg<'tcx>>,
response: CanonicalResponse<'tcx>,
) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty) {
param_env: I::ParamEnv,
original_values: Vec<I::GenericArg>,
response: CanonicalResponse<I>,
) -> (NestedNormalizationGoals<I>, Certainty) {
let instantiation = Self::compute_query_response_instantiation_values(
self.infcx,
&original_values,
@ -251,7 +224,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
);
let Response { var_values, external_constraints, certainty } =
response.instantiate(self.interner(), &instantiation);
self.infcx.instantiate_canonical(response, instantiation);
Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values);
@ -259,7 +232,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
region_constraints,
opaque_types,
normalization_nested_goals,
} = external_constraints.deref();
} = &*external_constraints;
self.register_region_constraints(region_constraints);
self.register_new_opaque_types(opaque_types);
(normalization_nested_goals.clone(), certainty)
@ -268,11 +241,11 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// This returns the canoncial variable values to instantiate the bound variables of
/// the canonical response. This depends on the `original_values` for the
/// bound variables.
fn compute_query_response_instantiation_values<T: ResponseT<'tcx>>(
infcx: &InferCtxt<'tcx>,
original_values: &[ty::GenericArg<'tcx>],
response: &Canonical<'tcx, T>,
) -> CanonicalVarValues<TyCtxt<'tcx>> {
fn compute_query_response_instantiation_values<T: ResponseT<I>>(
infcx: &Infcx,
original_values: &[I::GenericArg],
response: &Canonical<I, T>,
) -> CanonicalVarValues<I> {
// FIXME: Longterm canonical queries should deal with all placeholders
// created inside of the query directly instead of returning them to the
// caller.
@ -294,35 +267,35 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// inference variable of the input right away, which is more performant.
let mut opt_values = IndexVec::from_elem_n(None, response.variables.len());
for (original_value, result_value) in iter::zip(original_values, var_values.var_values) {
match result_value.unpack() {
GenericArgKind::Type(t) => {
if let &ty::Bound(debruijn, b) = t.kind() {
match result_value.kind() {
ty::GenericArgKind::Type(t) => {
if let ty::Bound(debruijn, b) = t.kind() {
assert_eq!(debruijn, ty::INNERMOST);
opt_values[b.var] = Some(*original_value);
opt_values[b.var()] = Some(*original_value);
}
}
GenericArgKind::Lifetime(r) => {
if let ty::ReBound(debruijn, br) = *r {
ty::GenericArgKind::Lifetime(r) => {
if let ty::ReBound(debruijn, br) = r.kind() {
assert_eq!(debruijn, ty::INNERMOST);
opt_values[br.var] = Some(*original_value);
opt_values[br.var()] = Some(*original_value);
}
}
GenericArgKind::Const(c) => {
if let ty::ConstKind::Bound(debruijn, b) = c.kind() {
ty::GenericArgKind::Const(c) => {
if let ty::ConstKind::Bound(debruijn, bv) = c.kind() {
assert_eq!(debruijn, ty::INNERMOST);
opt_values[b] = Some(*original_value);
opt_values[bv.var()] = Some(*original_value);
}
}
}
}
let var_values = infcx.tcx.mk_args_from_iter(response.variables.iter().enumerate().map(
|(index, info)| {
let var_values = infcx.interner().mk_args_from_iter(
response.variables.into_iter().enumerate().map(|(index, info)| {
if info.universe() != ty::UniverseIndex::ROOT {
// A variable from inside a binder of the query. While ideally these shouldn't
// exist at all (see the FIXME at the start of this method), we have to deal with
// them for now.
infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| {
infcx.instantiate_canonical_var_with_infer(info, |idx| {
ty::UniverseIndex::from(prev_universe.index() + idx.index())
})
} else if info.is_existential() {
@ -333,18 +306,18 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// more placeholders then they should be able to. However the inference variables have
// to "come from somewhere", so by equating them with the original values of the caller
// later on, we pull them down into their correct universe again.
if let Some(v) = opt_values[BoundVar::from_usize(index)] {
if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] {
v
} else {
infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe)
infcx.instantiate_canonical_var_with_infer(info, |_| prev_universe)
}
} else {
// For placeholders which were already part of the input, we simply map this
// universal bound variable back the placeholder of the input.
original_values[info.expect_placeholder_index()]
}
},
));
}),
);
CanonicalVarValues { var_values }
}
@ -363,40 +336,35 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// always relate them structurally here.
#[instrument(level = "trace", skip(infcx))]
fn unify_query_var_values(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
original_values: &[ty::GenericArg<'tcx>],
var_values: CanonicalVarValues<TyCtxt<'tcx>>,
infcx: &Infcx,
param_env: I::ParamEnv,
original_values: &[I::GenericArg],
var_values: CanonicalVarValues<I>,
) {
assert_eq!(original_values.len(), var_values.len());
let cause = ObligationCause::dummy();
for (&orig, response) in iter::zip(original_values, var_values.var_values) {
let InferOk { value: (), obligations } = infcx
.at(&cause, param_env)
.eq_structurally_relating_aliases(orig, response)
.unwrap();
assert!(obligations.is_empty());
let goals = infcx.eq_structurally_relating_aliases(param_env, orig, response).unwrap();
assert!(goals.is_empty());
}
}
fn register_region_constraints(
&mut self,
outlives: &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>],
outlives: &[ty::OutlivesPredicate<I, I::GenericArg>],
) {
for &ty::OutlivesPredicate(lhs, rhs) in outlives {
match lhs.unpack() {
GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"),
match lhs.kind() {
ty::GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
ty::GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"),
}
}
}
fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) {
fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)]) {
for &(key, ty) in opaque_types {
let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP };
self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty);
self.infcx.inject_new_hidden_type_unchecked(key, ty);
}
}
}
@ -412,7 +380,7 @@ pub(in crate::solve) fn make_canonical_state<Infcx, T, I>(
data: T,
) -> inspect::CanonicalState<I, T>
where
Infcx: IrSolverDelegate<Interner = I>,
Infcx: SolverDelegate<Interner = I>,
I: Interner,
T: TypeFoldable<I>,
{
@ -426,47 +394,3 @@ where
state,
)
}
/// Instantiate a `CanonicalState`.
///
/// Unlike for query responses, `CanonicalState` also track fresh inference
/// variables created while evaluating a goal. When creating two separate
/// `CanonicalState` during a single evaluation both may reference this
/// fresh inference variable. When instantiating them we now create separate
/// inference variables for it and have to unify them somehow. We do this
/// by extending the `var_values` while building the proof tree.
///
/// This currently assumes that unifying the var values trivially succeeds.
/// Adding any inference constraints which weren't present when originally
/// computing the canonical query can result in bugs.
#[instrument(level = "trace", skip(infcx, span, param_env))]
pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
infcx: &InferCtxt<'tcx>,
span: Span,
param_env: ty::ParamEnv<'tcx>,
orig_values: &mut Vec<ty::GenericArg<'tcx>>,
state: inspect::CanonicalState<TyCtxt<'tcx>, T>,
) -> T {
// In case any fresh inference variables have been created between `state`
// and the previous instantiation, extend `orig_values` for it.
assert!(orig_values.len() <= state.value.var_values.len());
for i in orig_values.len()..state.value.var_values.len() {
let unconstrained = match state.value.var_values.var_values[i].unpack() {
ty::GenericArgKind::Lifetime(_) => {
infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)).into()
}
ty::GenericArgKind::Type(_) => infcx.next_ty_var(span).into(),
ty::GenericArgKind::Const(_) => infcx.next_const_var(span).into(),
};
orig_values.push(unconstrained);
}
let instantiation =
EvalCtxt::compute_query_response_instantiation_values(infcx, orig_values, &state);
let inspect::State { var_values, data } = state.instantiate(infcx.tcx, &instantiation);
EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values);
data
}

View File

@ -1,41 +1,29 @@
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals};
use rustc_infer::traits::ObligationCause;
use rustc_macros::{extension, HashStable, HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_middle::bug;
use rustc_middle::traits::solve::{
inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
};
use rustc_middle::ty::AliasRelationDirection;
use rustc_middle::ty::TypeFolder;
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_next_trait_solver::infcx::SolverDelegate as IrSolverDelegate;
use rustc_span::DUMMY_SP;
use rustc_type_ir::fold::TypeSuperFoldable;
use rustc_type_ir::inherent::*;
use rustc_type_ir::relate::Relate;
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use std::ops::ControlFlow;
use crate::solve::infcx::SolverDelegate;
use crate::traits::coherence;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::inherent::*;
use rustc_type_ir::relate::Relate;
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
use rustc_type_ir::{self as ty, CanonicalVarValues, Interner};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use super::inspect::ProofTreeBuilder;
use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT};
use super::{search_graph::SearchGraph, Goal};
use super::{GoalSource, SolverMode};
use crate::infcx::SolverDelegate;
use crate::solve::inspect::{self, ProofTreeBuilder};
use crate::solve::search_graph::SearchGraph;
use crate::solve::{
search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind,
GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData,
QueryResult, SolverMode, FIXPOINT_STEP_LIMIT,
};
pub(super) mod canonical;
mod probe;
pub struct EvalCtxt<'a, Infcx, I = <Infcx as IrSolverDelegate>::Interner>
pub struct EvalCtxt<'a, Infcx, I = <Infcx as SolverDelegate>::Interner>
where
Infcx: IrSolverDelegate<Interner = I>,
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
/// The inference context that backs (mostly) inference and placeholder terms
@ -112,9 +100,9 @@ pub struct NestedGoals<I: Interner> {
///
/// Forgetting to replace the RHS with a fresh inference variable when we evaluate
/// this goal results in an ICE..
pub normalizes_to_goals: Vec<ir::solve::Goal<I, ir::NormalizesTo<I>>>,
pub normalizes_to_goals: Vec<Goal<I, ty::NormalizesTo<I>>>,
/// The rest of the goals which have not yet processed or remain ambiguous.
pub goals: Vec<(GoalSource, ir::solve::Goal<I, I::Predicate>)>,
pub goals: Vec<(GoalSource, Goal<I, I::Predicate>)>,
}
impl<I: Interner> NestedGoals<I> {
@ -127,14 +115,25 @@ impl<I: Interner> NestedGoals<I> {
}
}
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
#[derive(PartialEq, Eq, Debug, Hash, HashStable_NoContext, Clone, Copy)]
pub enum GenerateProofTree {
Yes,
No,
}
#[extension(pub trait InferCtxtEvalExt<'tcx>)]
impl<'tcx> InferCtxt<'tcx> {
pub trait SolverDelegateEvalExt: SolverDelegate {
fn evaluate_root_goal(
&self,
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
generate_proof_tree: GenerateProofTree,
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<Self::Interner>>);
}
impl<Infcx, I> SolverDelegateEvalExt for Infcx
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
/// Evaluates a goal from **outside** of the trait solver.
///
/// Using this while inside of the solver is wrong as it uses a new
@ -142,17 +141,20 @@ impl<'tcx> InferCtxt<'tcx> {
#[instrument(level = "debug", skip(self))]
fn evaluate_root_goal(
&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
goal: Goal<I, I::Predicate>,
generate_proof_tree: GenerateProofTree,
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>)
{
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) {
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
})
}
}
impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
impl<'a, Infcx, I> EvalCtxt<'a, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
pub(super) fn solver_mode(&self) -> SolverMode {
self.search_graph.solver_mode()
}
@ -163,17 +165,16 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
/// Creates a root evaluation context and search graph. This should only be
/// used from outside of any evaluation, and other methods should be preferred
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
/// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]).
pub(super) fn enter_root<R>(
infcx: &InferCtxt<'tcx>,
infcx: &Infcx,
generate_proof_tree: GenerateProofTree,
f: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>) -> R,
) -> (R, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) {
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
let mut search_graph = search_graph::SearchGraph::new(mode);
f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> R,
) -> (R, Option<inspect::GoalEvaluation<I>>) {
let mut search_graph = search_graph::SearchGraph::new(infcx.solver_mode());
let mut ecx = EvalCtxt {
infcx: <&SolverDelegate<'tcx>>::from(infcx),
infcx,
search_graph: &mut search_graph,
nested_goals: NestedGoals::new(),
inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree),
@ -181,10 +182,10 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
// Only relevant when canonicalizing the response,
// which we don't do within this evaluation context.
predefined_opaques_in_body: infcx
.tcx
.interner()
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
max_input_universe: ty::UniverseIndex::ROOT,
variables: ty::List::empty(),
variables: Default::default(),
var_values: CanonicalVarValues::dummy(),
is_normalizes_to_goal: false,
tainted: Ok(()),
@ -210,24 +211,17 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
/// This function takes care of setting up the inference context, setting the anchor,
/// and registering opaques from the canonicalized input.
fn enter_canonical<R>(
tcx: TyCtxt<'tcx>,
search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
canonical_input: CanonicalInput<'tcx>,
canonical_goal_evaluation: &mut ProofTreeBuilder<SolverDelegate<'tcx>>,
f: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
tcx: I,
search_graph: &'a mut search_graph::SearchGraph<I>,
canonical_input: CanonicalInput<I>,
canonical_goal_evaluation: &mut ProofTreeBuilder<Infcx>,
f: impl FnOnce(&mut EvalCtxt<'_, Infcx>, Goal<I, I::Predicate>) -> R,
) -> R {
let intercrate = match search_graph.solver_mode() {
SolverMode::Normal => false,
SolverMode::Coherence => true,
};
let (ref infcx, input, var_values) = tcx
.infer_ctxt()
.intercrate(intercrate)
.with_next_trait_solver(true)
.build_with_canonical(DUMMY_SP, &canonical_input);
let (ref infcx, input, var_values) =
SolverDelegate::build_with_canonical(tcx, search_graph.solver_mode(), &canonical_input);
let mut ecx = EvalCtxt {
infcx: <&SolverDelegate<'tcx>>::from(infcx),
infcx,
variables: canonical_input.variables,
var_values,
is_normalizes_to_goal: false,
@ -240,8 +234,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
};
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP };
ecx.infcx.inject_new_hidden_type_unchecked(key, hidden_ty);
ecx.infcx.inject_new_hidden_type_unchecked(key, ty);
}
if !ecx.nested_goals.is_empty() {
@ -256,7 +249,8 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
// instead of taking them. This would cause an ICE here, since we have
// assertions against dropping an `InferCtxt` without taking opaques.
// FIXME: Once we remove support for the old impl we can remove this.
let _ = infcx.take_opaque_types();
// FIXME: Could we make `build_with_canonical` into `enter_with_canonical` and call this at the end?
infcx.reset_opaque_types();
result
}
@ -268,15 +262,15 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
/// logic of the solver.
///
/// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal]
/// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're
/// if you're inside of the solver or [SolverDelegateEvalExt::evaluate_root_goal] if you're
/// outside of it.
#[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)]
fn evaluate_canonical_goal(
tcx: TyCtxt<'tcx>,
search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
canonical_input: CanonicalInput<'tcx>,
goal_evaluation: &mut ProofTreeBuilder<SolverDelegate<'tcx>>,
) -> QueryResult<'tcx> {
tcx: I,
search_graph: &'a mut search_graph::SearchGraph<I>,
canonical_input: CanonicalInput<I>,
goal_evaluation: &mut ProofTreeBuilder<Infcx>,
) -> QueryResult<I> {
let mut canonical_goal_evaluation =
goal_evaluation.new_canonical_goal_evaluation(canonical_input);
@ -315,7 +309,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
&mut self,
goal_evaluation_kind: GoalEvaluationKind,
source: GoalSource,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
goal: Goal<I, I::Predicate>,
) -> Result<(bool, Certainty), NoSolution> {
let (normalization_nested_goals, has_changed, certainty) =
self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?;
@ -336,8 +330,8 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
&mut self,
goal_evaluation_kind: GoalEvaluationKind,
_source: GoalSource,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
) -> Result<(NestedNormalizationGoals<TyCtxt<'tcx>>, bool, Certainty), NoSolution> {
goal: Goal<I, I::Predicate>,
) -> Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution> {
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
let mut goal_evaluation =
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
@ -377,10 +371,10 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
fn instantiate_response_discarding_overflow(
&mut self,
param_env: ty::ParamEnv<'tcx>,
original_values: Vec<ty::GenericArg<'tcx>>,
response: CanonicalResponse<'tcx>,
) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty, bool) {
param_env: I::ParamEnv,
original_values: Vec<I::GenericArg>,
response: CanonicalResponse<I>,
) -> (NestedNormalizationGoals<I>, Certainty, bool) {
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty {
return (NestedNormalizationGoals::empty(), response.value.certainty, false);
}
@ -393,7 +387,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
(normalization_nested_goals, certainty, has_changed)
}
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
let Goal { param_env, predicate } = goal;
let kind = predicate.kind();
if let Some(kind) = kind.no_bound_vars() {
@ -429,7 +423,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
}
ty::PredicateKind::ConstEquate(_, _) => {
bug!("ConstEquate should not be emitted when `-Znext-solver` is active")
panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
}
ty::PredicateKind::NormalizesTo(predicate) => {
self.compute_normalizes_to_goal(Goal { param_env, predicate })
@ -565,21 +559,16 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
}
/// Record impl args in the proof tree for later access by `InspectCandidate`.
pub(crate) fn record_impl_args(&mut self, impl_args: ty::GenericArgsRef<'tcx>) {
pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) {
self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args)
}
}
impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
pub(super) fn interner(&self) -> I {
self.infcx.interner()
}
#[instrument(level = "trace", skip(self))]
pub(super) fn add_normalizes_to_goal(
&mut self,
mut goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
) {
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
goal.predicate = goal
.predicate
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
@ -588,11 +577,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
}
#[instrument(level = "debug", skip(self))]
pub(super) fn add_goal(
&mut self,
source: GoalSource,
mut goal: ir::solve::Goal<I, I::Predicate>,
) {
pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
goal.predicate = goal
.predicate
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
@ -604,7 +589,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
pub(super) fn add_goals(
&mut self,
source: GoalSource,
goals: impl IntoIterator<Item = ir::solve::Goal<I, I::Predicate>>,
goals: impl IntoIterator<Item = Goal<I, I::Predicate>>,
) {
for goal in goals {
self.add_goal(source, goal);
@ -627,8 +612,8 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
/// If `kind` is an integer inference variable this will still return a ty infer var.
pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term {
match kind.kind() {
ir::TermKind::Ty(_) => self.next_ty_infer().into(),
ir::TermKind::Const(_) => self.next_const_infer().into(),
ty::TermKind::Ty(_) => self.next_ty_infer().into(),
ty::TermKind::Const(_) => self.next_const_infer().into(),
}
}
@ -637,20 +622,17 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
/// This is the case if the `term` does not occur in any other part of the predicate
/// and is able to name all other placeholder and inference variables.
#[instrument(level = "trace", skip(self), ret)]
pub(super) fn term_is_fully_unconstrained(
&self,
goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
) -> bool {
pub(super) fn term_is_fully_unconstrained(&self, goal: Goal<I, ty::NormalizesTo<I>>) -> bool {
let universe_of_term = match goal.predicate.term.kind() {
ir::TermKind::Ty(ty) => {
if let ir::Infer(ir::TyVar(vid)) = ty.kind() {
ty::TermKind::Ty(ty) => {
if let ty::Infer(ty::TyVar(vid)) = ty.kind() {
self.infcx.universe_of_ty(vid).unwrap()
} else {
return false;
}
}
ir::TermKind::Const(ct) => {
if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() {
ty::TermKind::Const(ct) => {
if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
self.infcx.universe_of_ct(vid).unwrap()
} else {
return false;
@ -658,14 +640,14 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
}
};
struct ContainsTermOrNotNameable<'a, Infcx: IrSolverDelegate<Interner = I>, I: Interner> {
struct ContainsTermOrNotNameable<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> {
term: I::Term,
universe_of_term: ir::UniverseIndex,
universe_of_term: ty::UniverseIndex,
infcx: &'a Infcx,
}
impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> {
fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> {
impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> {
fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
if self.universe_of_term.can_name(universe) {
ControlFlow::Continue(())
} else {
@ -674,15 +656,15 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
}
}
impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> TypeVisitor<I>
impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I>
for ContainsTermOrNotNameable<'_, Infcx, I>
{
type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
match t.kind() {
ir::Infer(ir::TyVar(vid)) => {
if let ir::TermKind::Ty(term) = self.term.kind()
&& let ir::Infer(ir::TyVar(term_vid)) = term.kind()
ty::Infer(ty::TyVar(vid)) => {
if let ty::TermKind::Ty(term) = self.term.kind()
&& let ty::Infer(ty::TyVar(term_vid)) = term.kind()
&& self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid)
{
ControlFlow::Break(())
@ -690,7 +672,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
self.check_nameable(self.infcx.universe_of_ty(vid).unwrap())
}
}
ir::Placeholder(p) => self.check_nameable(p.universe()),
ty::Placeholder(p) => self.check_nameable(p.universe()),
_ => {
if t.has_non_region_infer() || t.has_placeholders() {
t.super_visit_with(self)
@ -703,9 +685,9 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
fn visit_const(&mut self, c: I::Const) -> Self::Result {
match c.kind() {
ir::ConstKind::Infer(ir::InferConst::Var(vid)) => {
if let ir::TermKind::Const(term) = self.term.kind()
&& let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = term.kind()
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
if let ty::TermKind::Const(term) = self.term.kind()
&& let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
&& self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid)
{
ControlFlow::Break(())
@ -713,7 +695,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
self.check_nameable(self.infcx.universe_of_ct(vid).unwrap())
}
}
ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
_ => {
if c.has_non_region_infer() || c.has_placeholders() {
c.super_visit_with(self)
@ -741,7 +723,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
lhs: T,
rhs: T,
) -> Result<(), NoSolution> {
self.relate(param_env, lhs, ir::Variance::Invariant, rhs)
self.relate(param_env, lhs, ty::Variance::Invariant, rhs)
}
/// This should be used when relating a rigid alias with another type.
@ -753,8 +735,8 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
pub(super) fn relate_rigid_alias_non_alias(
&mut self,
param_env: I::ParamEnv,
alias: ir::AliasTerm<I>,
variance: ir::Variance,
alias: ty::AliasTerm<I>,
variance: ty::Variance,
term: I::Term,
) -> Result<(), NoSolution> {
// NOTE: this check is purely an optimization, the structural eq would
@ -770,7 +752,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
// Alternatively we could modify `Equate` for this case by adding another
// variant to `StructurallyRelateAliases`.
let identity_args = self.fresh_args_for_item(alias.def_id);
let rigid_ctor = ir::AliasTerm::new(tcx, alias.def_id, identity_args);
let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args);
let ctor_term = rigid_ctor.to_term(tcx);
let obligations =
self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?;
@ -803,7 +785,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
sub: T,
sup: T,
) -> Result<(), NoSolution> {
self.relate(param_env, sub, ir::Variance::Covariant, sup)
self.relate(param_env, sub, ty::Variance::Covariant, sup)
}
#[instrument(level = "trace", skip(self, param_env), ret)]
@ -811,7 +793,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
&mut self,
param_env: I::ParamEnv,
lhs: T,
variance: ir::Variance,
variance: ty::Variance,
rhs: T,
) -> Result<(), NoSolution> {
let goals = self.infcx.relate(param_env, lhs, variance, rhs)?;
@ -830,20 +812,20 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
param_env: I::ParamEnv,
lhs: T,
rhs: T,
) -> Result<Vec<ir::solve::Goal<I, I::Predicate>>, NoSolution> {
self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs)
) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
self.infcx.relate(param_env, lhs, ty::Variance::Invariant, rhs)
}
pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
&self,
value: ir::Binder<I, T>,
value: ty::Binder<I, T>,
) -> T {
self.infcx.instantiate_binder_with_infer(value)
}
pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
&self,
value: ir::Binder<I, T>,
value: ty::Binder<I, T>,
f: impl FnOnce(T) -> U,
) -> U {
self.infcx.enter_forall(value, f)
@ -863,36 +845,29 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
}
args
}
pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
self.infcx.register_ty_outlives(ty, lt);
}
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
}
pub(super) fn register_region_outlives(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) {
pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) {
// `b : a` ==> `a <= b`
// (inlined from `InferCtxt::region_outlives_predicate`)
self.infcx.sub_regions(
rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP),
b,
a,
);
self.infcx.sub_regions(b, a);
}
/// Computes the list of goals required for `arg` to be well-formed
pub(super) fn well_formed_goals(
&self,
param_env: ty::ParamEnv<'tcx>,
arg: ty::GenericArg<'tcx>,
) -> Option<impl Iterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>> {
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
param_env: I::ParamEnv,
arg: I::GenericArg,
) -> Option<Vec<Goal<I, I::Predicate>>> {
self.infcx.well_formed_goals(param_env, arg)
}
/*
pub(super) fn is_transmutable(
&self,
src_and_dst: rustc_transmute::Types<'tcx>,
src_and_dst: rustc_transmute::Types<I>,
assume: rustc_transmute::Assume,
) -> Result<Certainty, NoSolution> {
use rustc_transmute::Answer;
@ -906,46 +881,55 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
Answer::No(_) | Answer::If(_) => Err(NoSolution),
}
}
*/
pub(super) fn trait_ref_is_knowable(
&mut self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
param_env: I::ParamEnv,
trait_ref: ty::TraitRef<I>,
) -> Result<bool, NoSolution> {
let infcx = self.infcx;
let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
coherence::trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty)
.map(|is_knowable| is_knowable.is_ok())
infcx.trait_ref_is_knowable(trait_ref, lazily_normalize_ty)
}
pub(super) fn can_define_opaque_ty(&self, def_id: impl Into<DefId>) -> bool {
self.infcx.can_define_opaque_ty(def_id)
pub(super) fn fetch_eligible_assoc_item(
&self,
param_env: I::ParamEnv,
goal_trait_ref: ty::TraitRef<I>,
trait_assoc_def_id: I::DefId,
impl_def_id: I::DefId,
) -> Result<Option<I::DefId>, NoSolution> {
self.infcx.fetch_eligible_assoc_item(
param_env,
goal_trait_ref,
trait_assoc_def_id,
impl_def_id,
)
}
pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool {
self.infcx.defining_opaque_types().contains(&def_id)
}
pub(super) fn insert_hidden_type(
&mut self,
opaque_type_key: OpaqueTypeKey<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
opaque_type_key: ty::OpaqueTypeKey<I>,
param_env: I::ParamEnv,
hidden_ty: I::Ty,
) -> Result<(), NoSolution> {
let mut goals = Vec::new();
self.infcx.insert_hidden_type(
opaque_type_key,
DUMMY_SP,
param_env,
hidden_ty,
&mut goals,
)?;
self.infcx.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?;
self.add_goals(GoalSource::Misc, goals);
Ok(())
}
pub(super) fn add_item_bounds_for_hidden_type(
&mut self,
opaque_def_id: DefId,
opaque_args: ty::GenericArgsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
opaque_def_id: I::DefId,
opaque_args: I::GenericArgs,
param_env: I::ParamEnv,
hidden_ty: I::Ty,
) {
let mut goals = Vec::new();
self.infcx.add_item_bounds_for_hidden_type(
@ -962,10 +946,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// current inference context.
pub(super) fn unify_existing_opaque_tys(
&mut self,
param_env: ty::ParamEnv<'tcx>,
key: ty::OpaqueTypeKey<'tcx>,
ty: Ty<'tcx>,
) -> Vec<CanonicalResponse<'tcx>> {
param_env: I::ParamEnv,
key: ty::OpaqueTypeKey<I>,
ty: I::Ty,
) -> Vec<CanonicalResponse<I>> {
// FIXME: Super inefficient to be cloning this...
let opaques = self.infcx.clone_opaque_types_for_query_response();
@ -984,7 +968,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
}
ecx.eq(param_env, candidate_ty, ty)?;
ecx.add_item_bounds_for_hidden_type(
candidate_key.def_id.to_def_id(),
candidate_key.def_id.into(),
candidate_key.args,
param_env,
candidate_ty,
@ -1001,23 +985,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// as an ambiguity rather than no-solution.
pub(super) fn try_const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::UnevaluatedConst<'tcx>,
) -> Option<ty::Const<'tcx>> {
use rustc_middle::mir::interpret::ErrorHandled;
match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
Ok(Some(val)) => Some(ty::Const::new_value(
self.interner(),
val,
self.interner()
.type_of(unevaluated.def)
.instantiate(self.interner(), unevaluated.args),
)),
Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None,
Err(ErrorHandled::Reported(e, _)) => {
Some(ty::Const::new_error(self.interner(), e.into()))
}
}
param_env: I::ParamEnv,
unevaluated: ty::UnevaluatedConst<I>,
) -> Option<I::Const> {
self.infcx.try_const_eval_resolve(param_env, unevaluated)
}
}
@ -1030,7 +1001,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
struct ReplaceAliasWithInfer<'me, 'a, Infcx, I>
where
Infcx: IrSolverDelegate<Interner = I>,
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
ecx: &'me mut EvalCtxt<'a, Infcx>,
@ -1039,7 +1010,7 @@ where
impl<Infcx, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, Infcx, I>
where
Infcx: IrSolverDelegate<Interner = I>,
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
fn interner(&self) -> I {
@ -1048,16 +1019,16 @@ where
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
match ty.kind() {
ir::Alias(..) if !ty.has_escaping_bound_vars() => {
ty::Alias(..) if !ty.has_escaping_bound_vars() => {
let infer_ty = self.ecx.next_ty_infer();
let normalizes_to = ir::PredicateKind::AliasRelate(
let normalizes_to = ty::PredicateKind::AliasRelate(
ty.into(),
infer_ty.into(),
AliasRelationDirection::Equate,
ty::AliasRelationDirection::Equate,
);
self.ecx.add_goal(
GoalSource::Misc,
ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to),
Goal::new(self.interner(), self.param_env, normalizes_to),
);
infer_ty
}
@ -1067,16 +1038,16 @@ where
fn fold_const(&mut self, ct: I::Const) -> I::Const {
match ct.kind() {
ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
let infer_ct = self.ecx.next_const_infer();
let normalizes_to = ir::PredicateKind::AliasRelate(
let normalizes_to = ty::PredicateKind::AliasRelate(
ct.into(),
infer_ct.into(),
AliasRelationDirection::Equate,
ty::AliasRelationDirection::Equate,
);
self.ecx.add_goal(
GoalSource::Misc,
ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to),
Goal::new(self.interner(), self.param_env, normalizes_to),
);
infer_ct
}

View File

@ -1,13 +1,12 @@
use crate::solve::assembly::Candidate;
use super::EvalCtxt;
use rustc_next_trait_solver::infcx::SolverDelegate;
use rustc_next_trait_solver::solve::{
inspect, BuiltinImplSource, CandidateSource, NoSolution, QueryResult,
};
use rustc_type_ir::Interner;
use std::marker::PhantomData;
use rustc_type_ir::Interner;
use crate::infcx::SolverDelegate;
use crate::solve::assembly::Candidate;
use crate::solve::inspect;
use crate::solve::{BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult};
pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T>
where
Infcx: SolverDelegate<Interner = I>,

View File

@ -3,18 +3,20 @@
//! This code is *a bit* of a mess and can hopefully be
//! mostly ignored. For a general overview of how it works,
//! see the comment on [ProofTreeBuilder].
use std::marker::PhantomData;
use std::mem;
use crate::solve::eval_ctxt::canonical;
use crate::solve::{self, inspect, GenerateProofTree};
use rustc_middle::bug;
use rustc_next_trait_solver::infcx::SolverDelegate;
use rustc_next_trait_solver::solve::{
CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult,
};
use rustc_type_ir::{self as ty, Interner};
use crate::infcx::SolverDelegate;
use crate::solve::eval_ctxt::canonical;
use crate::solve::inspect;
use crate::solve::{
CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput,
QueryResult,
};
/// The core data structure when building proof trees.
///
/// In case the current evaluation does not generate a proof
@ -171,7 +173,7 @@ impl<I: Interner> WipCanonicalGoalEvaluationStep<I> {
for _ in 0..self.probe_depth {
match current.steps.last_mut() {
Some(WipProbeStep::NestedProbe(p)) => current = p,
_ => bug!(),
_ => panic!(),
}
}
current
@ -294,15 +296,15 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
&mut self,
goal: Goal<I, I::Predicate>,
orig_values: &[I::GenericArg],
kind: solve::GoalEvaluationKind,
kind: GoalEvaluationKind,
) -> ProofTreeBuilder<Infcx> {
self.opt_nested(|| match kind {
solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation {
GoalEvaluationKind::Root => Some(WipGoalEvaluation {
uncanonicalized_goal: goal,
orig_values: orig_values.to_vec(),
evaluation: None,
}),
solve::GoalEvaluationKind::Nested => None,
GoalEvaluationKind::Nested => None,
})
}
@ -414,7 +416,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
state.var_values.push(arg.into());
}
Some(s) => bug!("tried to add var values to {s:?}"),
Some(s) => panic!("tried to add var values to {s:?}"),
}
}
@ -431,7 +433,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
}));
state.probe_depth += 1;
}
Some(s) => bug!("tried to start probe to {s:?}"),
Some(s) => panic!("tried to start probe to {s:?}"),
}
}
@ -442,7 +444,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
let prev = state.current_evaluation_scope().kind.replace(probe_kind);
assert_eq!(prev, None);
}
_ => bug!(),
_ => panic!(),
}
}
@ -459,7 +461,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
let prev = state.current_evaluation_scope().final_state.replace(final_state);
assert_eq!(prev, None);
}
_ => bug!(),
_ => panic!(),
}
}
@ -495,7 +497,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
);
state.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal))
}
_ => bug!(),
_ => panic!(),
}
}
@ -519,7 +521,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
.push(WipProbeStep::RecordImplArgs { impl_args });
}
None => {}
_ => bug!(),
_ => panic!(),
}
}
@ -532,7 +534,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
.push(WipProbeStep::MakeCanonicalResponse { shallow_certainty });
}
None => {}
_ => bug!(),
_ => panic!(),
}
}
@ -545,7 +547,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
state.var_values.truncate(num_var_values);
state.probe_depth -= 1;
}
_ => bug!(),
_ => panic!(),
}
self

View File

@ -0,0 +1,4 @@
pub use rustc_type_ir::solve::inspect::*;
mod build;
pub(in crate::solve) use build::*;

View File

@ -14,40 +14,22 @@
//! FIXME(@lcnr): Write that section. If you read this before then ask me
//! about it on zulip.
use self::infcx::SolverDelegate;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::traits::query::NoSolution;
use rustc_macros::extension;
use rustc_middle::bug;
use rustc_middle::traits::solve::{
CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, QueryResult, Response,
};
use rustc_middle::ty::{
self, AliasRelationDirection, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, Ty,
TyCtxt, TypeOutlivesPredicate, UniverseIndex,
};
use rustc_type_ir::solve::SolverMode;
use rustc_type_ir::{self as ir, Interner};
mod alias_relate;
mod assembly;
mod eval_ctxt;
mod fulfill;
mod infcx;
pub mod inspect;
mod normalize;
mod normalizes_to;
mod project_goals;
mod search_graph;
mod select;
mod trait_goals;
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt};
pub use fulfill::{FulfillmentCtxt, NextSolverError};
pub(crate) use normalize::deeply_normalize_for_diagnostics;
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
pub use select::InferCtxtSelectExt;
pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt};
pub use rustc_type_ir::solve::*;
use rustc_type_ir::inherent::*;
use rustc_type_ir::{self as ty, Interner};
use crate::infcx::SolverDelegate;
/// How many fixpoint iterations we should attempt inside of the solver before bailing
/// with overflow.
@ -66,21 +48,24 @@ enum GoalEvaluationKind {
Nested,
}
#[extension(trait CanonicalResponseExt)]
impl<'tcx> Canonical<'tcx, Response<TyCtxt<'tcx>>> {
fn has_no_inference_or_external_constraints(&self) -> bool {
self.value.external_constraints.region_constraints.is_empty()
&& self.value.var_values.is_identity()
&& self.value.external_constraints.opaque_types.is_empty()
}
fn has_no_inference_or_external_constraints<I: Interner>(
response: ty::Canonical<I, Response<I>>,
) -> bool {
response.value.external_constraints.region_constraints.is_empty()
&& response.value.var_values.is_identity()
&& response.value.external_constraints.opaque_types.is_empty()
}
impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
impl<'a, Infcx, I> EvalCtxt<'a, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "trace", skip(self))]
fn compute_type_outlives_goal(
&mut self,
goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, ty::OutlivesPredicate<I, I::Ty>>,
) -> QueryResult<I> {
let ty::OutlivesPredicate(ty, lt) = goal.predicate;
self.register_ty_outlives(ty, lt);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
@ -89,21 +74,18 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
#[instrument(level = "trace", skip(self))]
fn compute_region_outlives_goal(
&mut self,
goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, ty::OutlivesPredicate<I, I::Region>>,
) -> QueryResult<I> {
let ty::OutlivesPredicate(a, b) = goal.predicate;
self.register_region_outlives(a, b);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
#[instrument(level = "trace", skip(self))]
fn compute_coerce_goal(
&mut self,
goal: Goal<'tcx, CoercePredicate<'tcx>>,
) -> QueryResult<'tcx> {
fn compute_coerce_goal(&mut self, goal: Goal<I, ty::CoercePredicate<I>>) -> QueryResult<I> {
self.compute_subtype_goal(Goal {
param_env: goal.param_env,
predicate: SubtypePredicate {
predicate: ty::SubtypePredicate {
a_is_expected: false,
a: goal.predicate.a,
b: goal.predicate.b,
@ -112,10 +94,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
}
#[instrument(level = "trace", skip(self))]
fn compute_subtype_goal(
&mut self,
goal: Goal<'tcx, SubtypePredicate<'tcx>>,
) -> QueryResult<'tcx> {
fn compute_subtype_goal(&mut self, goal: Goal<I, ty::SubtypePredicate<I>>) -> QueryResult<I> {
if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
} else {
@ -124,8 +103,8 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
}
}
fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
if self.interner().is_object_safe(trait_def_id) {
fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult<I> {
if self.interner().trait_is_object_safe(trait_def_id) {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else {
Err(NoSolution)
@ -133,10 +112,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
}
#[instrument(level = "trace", skip(self))]
fn compute_well_formed_goal(
&mut self,
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
) -> QueryResult<'tcx> {
fn compute_well_formed_goal(&mut self, goal: Goal<I, I::GenericArg>) -> QueryResult<I> {
match self.well_formed_goals(goal.param_env, goal.predicate) {
Some(goals) => {
self.add_goals(GoalSource::Misc, goals);
@ -149,8 +125,8 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
#[instrument(level = "trace", skip(self))]
fn compute_const_evaluatable_goal(
&mut self,
Goal { param_env, predicate: ct }: Goal<'tcx, ty::Const<'tcx>>,
) -> QueryResult<'tcx> {
Goal { param_env, predicate: ct }: Goal<I, I::Const>,
) -> QueryResult<I> {
match ct.kind() {
ty::ConstKind::Unevaluated(uv) => {
// We never return `NoSolution` here as `try_const_eval_resolve` emits an
@ -180,7 +156,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
// - `Bound` cannot exist as we don't have a binder around the self Type
// - `Expr` is part of `feature(generic_const_exprs)` and is not implemented yet
ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Expr(_) => {
bug!("unexpect const kind: {:?}", ct)
panic!("unexpect const kind: {:?}", ct)
}
}
}
@ -188,8 +164,8 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
#[instrument(level = "trace", skip(self), ret)]
fn compute_const_arg_has_type_goal(
&mut self,
goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>,
) -> QueryResult<'tcx> {
goal: Goal<I, (I::Const, I::Ty)>,
) -> QueryResult<I> {
let (ct, ty) = goal.predicate;
let ct_ty = match ct.kind() {
@ -206,7 +182,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
ty::ConstKind::Unevaluated(uv) => {
self.interner().type_of(uv.def).instantiate(self.interner(), uv.args)
self.interner().type_of(uv.def).instantiate(self.interner(), &uv.args)
}
ty::ConstKind::Expr(_) => unimplemented!(
"`feature(generic_const_exprs)` is not supported in the new trait solver"
@ -214,10 +190,10 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
ty::ConstKind::Param(_) => {
unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`")
}
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct),
ty::ConstKind::Value(ty, _) => ty,
ty::ConstKind::Placeholder(placeholder) => {
placeholder.find_const_ty_from_env(goal.param_env)
self.interner().find_const_ty_from_env(goal.param_env, placeholder)
}
};
@ -226,15 +202,19 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
}
}
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
/// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`.
///
/// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
#[instrument(level = "trace", skip(self), ret)]
fn try_merge_responses(
&mut self,
responses: &[CanonicalResponse<'tcx>],
) -> Option<CanonicalResponse<'tcx>> {
responses: &[CanonicalResponse<I>],
) -> Option<CanonicalResponse<I>> {
if responses.is_empty() {
return None;
}
@ -250,14 +230,14 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
.iter()
.find(|response| {
response.value.certainty == Certainty::Yes
&& response.has_no_inference_or_external_constraints()
&& has_no_inference_or_external_constraints(**response)
})
.copied()
}
/// If we fail to merge responses we flounder and return overflow or ambiguity.
#[instrument(level = "trace", skip(self), ret)]
fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tcx> {
fn flounder(&mut self, responses: &[CanonicalResponse<I>]) -> QueryResult<I> {
if responses.is_empty() {
return Err(NoSolution);
}
@ -267,7 +247,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
certainty.unify_with(response.value.certainty)
})
else {
bug!("expected flounder response to be ambiguous")
panic!("expected flounder response to be ambiguous")
};
Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
@ -281,9 +261,9 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
#[instrument(level = "trace", skip(self, param_env), ret)]
fn structurally_normalize_ty(
&mut self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
) -> Result<Ty<'tcx>, NoSolution> {
param_env: I::ParamEnv,
ty: I::Ty,
) -> Result<I::Ty, NoSolution> {
if let ty::Alias(..) = ty.kind() {
let normalized_ty = self.next_ty_infer();
let alias_relate_goal = Goal::new(
@ -292,7 +272,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
ty::PredicateKind::AliasRelate(
ty.into(),
normalized_ty.into(),
AliasRelationDirection::Equate,
ty::AliasRelationDirection::Equate,
),
);
self.add_goal(GoalSource::Misc, alias_relate_goal);
@ -306,15 +286,15 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
fn response_no_constraints_raw<I: Interner>(
tcx: I,
max_universe: UniverseIndex,
max_universe: ty::UniverseIndex,
variables: I::CanonicalVars,
certainty: Certainty,
) -> ir::solve::CanonicalResponse<I> {
ir::Canonical {
) -> CanonicalResponse<I> {
ty::Canonical {
max_universe,
variables,
value: Response {
var_values: ir::CanonicalVarValues::make_identity(tcx, variables),
var_values: ty::CanonicalVarValues::make_identity(tcx, variables),
// FIXME: maybe we should store the "no response" version in tcx, like
// we do for tcx.types and stuff.
external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()),

View File

@ -1,14 +1,18 @@
use crate::solve::infcx::SolverDelegate;
use crate::solve::EvalCtxt;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty;
use rustc_type_ir::{self as ty, Interner};
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
use crate::infcx::SolverDelegate;
use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult};
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "trace", skip(self), ret)]
pub(super) fn normalize_anon_const(
&mut self,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, ty::NormalizesTo<I>>,
) -> QueryResult<I> {
if let Some(normalized_const) = self.try_const_eval_resolve(
goal.param_env,
ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),

View File

@ -5,17 +5,20 @@
//! 2. equate the self type, and
//! 3. instantiate and register where clauses.
use crate::solve::infcx::SolverDelegate;
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
use rustc_middle::ty;
use rustc_type_ir::{self as ty, Interner};
use crate::solve::EvalCtxt;
use crate::infcx::SolverDelegate;
use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult};
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
pub(super) fn normalize_inherent_associated_type(
&mut self,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, ty::NormalizesTo<I>>,
) -> QueryResult<I> {
let tcx = self.interner();
let inherent = goal.predicate.alias.expect_ty(tcx);
@ -26,7 +29,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
self.eq(
goal.param_env,
inherent.self_ty(),
tcx.type_of(impl_def_id).instantiate(tcx, impl_args),
tcx.type_of(impl_def_id).instantiate(tcx, &impl_args),
)?;
// Equate IAT with the RHS of the project goal
@ -41,12 +44,11 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
self.add_goals(
GoalSource::Misc,
tcx.predicates_of(inherent.def_id)
.instantiate(tcx, inherent_args)
.into_iter()
.map(|(pred, _)| goal.with(tcx, pred)),
.iter_instantiated(tcx, &inherent_args)
.map(|pred| goal.with(tcx, pred)),
);
let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, inherent_args);
let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, &inherent_args);
self.instantiate_normalizes_to_term(goal, normalized.into());
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}

View File

@ -1,35 +1,32 @@
use crate::traits::specialization_graph::{self, LeafDef, Node};
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
use super::assembly::{self, structural_traits, Candidate};
use super::infcx::SolverDelegate;
use super::{EvalCtxt, GoalSource};
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::inspect::ProbeKind;
use rustc_infer::traits::solve::MaybeCause;
use rustc_infer::traits::Reveal;
use rustc_middle::bug;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
use rustc_middle::traits::BuiltinImplSource;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::NormalizesTo;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{TypeVisitableExt, Upcast};
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
mod anon_const;
mod inherent;
mod opaque_types;
mod weak_types;
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::Upcast as _;
use rustc_type_ir::{self as ty, Interner, NormalizesTo};
use crate::infcx::SolverDelegate;
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
use crate::solve::assembly::{self, Candidate};
use crate::solve::inspect::ProbeKind;
use crate::solve::{
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
NoSolution, QueryResult,
};
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "trace", skip(self), ret)]
pub(super) fn compute_normalizes_to_goal(
&mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, NormalizesTo<I>>,
) -> QueryResult<I> {
self.set_is_normalizes_to_goal();
debug_assert!(self.term_is_fully_unconstrained(goal));
let normalize_result = self
@ -49,10 +46,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// Normalize the given alias by at least one step. If the alias is rigid, this
/// returns `NoSolution`.
#[instrument(level = "trace", skip(self), ret)]
fn normalize_at_least_one_step(
&mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
fn normalize_at_least_one_step(&mut self, goal: Goal<I, NormalizesTo<I>>) -> QueryResult<I> {
match goal.predicate.alias.kind(self.interner()) {
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
let candidates = self.assemble_and_evaluate_candidates(goal);
@ -72,38 +66,42 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// emit nested `AliasRelate` goals to structurally normalize the alias.
pub fn instantiate_normalizes_to_term(
&mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>,
term: ty::Term<'tcx>,
goal: Goal<I, NormalizesTo<I>>,
term: I::Term,
) {
self.eq(goal.param_env, goal.predicate.term, term)
.expect("expected goal term to be fully unconstrained");
}
}
impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
fn self_ty(self) -> Ty<'tcx> {
impl<Infcx, I> assembly::GoalKind<Infcx> for NormalizesTo<I>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
fn self_ty(self) -> I::Ty {
self.self_ty()
}
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
fn trait_ref(self, tcx: I) -> ty::TraitRef<I> {
self.alias.trait_ref(tcx)
}
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self {
self.with_self_ty(tcx, self_ty)
}
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
fn trait_def_id(self, tcx: I) -> I::DefId {
self.trait_def_id(tcx)
}
fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
source: CandidateSource<'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
then: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>) -> QueryResult<'tcx>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
source: CandidateSource<I>,
goal: Goal<I, Self>,
assumption: I::Clause,
then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
) -> Result<Candidate<I>, NoSolution> {
if let Some(projection_pred) = assumption.as_projection_clause() {
if projection_pred.projection_def_id() == goal.predicate.def_id() {
let tcx = ecx.interner();
@ -121,9 +119,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
// Add GAT where clauses from the trait's definition
ecx.add_goals(
GoalSource::Misc,
tcx.predicates_of(goal.predicate.def_id())
.instantiate_own(tcx, goal.predicate.alias.args)
.map(|(pred, _)| goal.with(tcx, pred)),
tcx.own_predicates_of(goal.predicate.def_id())
.iter_instantiated(tcx, &goal.predicate.alias.args)
.map(|pred| goal.with(tcx, pred)),
);
then(ecx)
@ -137,24 +135,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, NormalizesTo<'tcx>>,
impl_def_id: DefId,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, NormalizesTo<I>>,
impl_def_id: I::DefId,
) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner();
let goal_trait_ref = goal.predicate.alias.trait_ref(tcx);
let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
if !drcx.args_may_unify(
goal.predicate.trait_ref(tcx).args,
impl_trait_header.trait_ref.skip_binder().args,
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
if !ecx.interner().args_may_unify_deep(
goal.predicate.alias.trait_ref(tcx).args,
impl_trait_ref.skip_binder().args,
) {
return Err(NoSolution);
}
// We have to ignore negative impls when projecting.
let impl_polarity = impl_trait_header.polarity;
let impl_polarity = tcx.impl_polarity(impl_def_id);
match impl_polarity {
ty::ImplPolarity::Negative => return Err(NoSolution),
ty::ImplPolarity::Reservation => {
@ -165,30 +162,28 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
let impl_args = ecx.fresh_args_for_item(impl_def_id);
let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args);
let impl_trait_ref = impl_trait_ref.instantiate(tcx, &impl_args);
ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
let where_clause_bounds = tcx
.predicates_of(impl_def_id)
.instantiate(tcx, impl_args)
.predicates
.into_iter()
.iter_instantiated(tcx, &impl_args)
.map(|pred| goal.with(tcx, pred));
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
// Add GAT where clauses from the trait's definition
ecx.add_goals(
GoalSource::Misc,
tcx.predicates_of(goal.predicate.def_id())
.instantiate_own(tcx, goal.predicate.alias.args)
.map(|(pred, _)| goal.with(tcx, pred)),
tcx.own_predicates_of(goal.predicate.def_id())
.iter_instantiated(tcx, &goal.predicate.alias.args)
.map(|pred| goal.with(tcx, pred)),
);
// In case the associated item is hidden due to specialization, we have to
// return ambiguity this would otherwise be incomplete, resulting in
// unsoundness during coherence (#105782).
let Some(assoc_def) = ecx.fetch_eligible_assoc_item_def(
let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item(
goal.param_env,
goal_trait_ref,
goal.predicate.def_id(),
@ -198,21 +193,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
};
let error_response = |ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, reason| {
let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason);
let error_response = |ecx: &mut EvalCtxt<'_, Infcx>, msg: &str| {
let guar = tcx.delay_bug(msg);
let error_term = match goal.predicate.alias.kind(tcx) {
ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(),
ty::AliasTermKind::ProjectionConst => ty::Const::new_error(tcx, guar).into(),
kind => bug!("expected projection, found {kind:?}"),
ty::AliasTermKind::ProjectionConst => Const::new_error(tcx, guar).into(),
kind => panic!("expected projection, found {kind:?}"),
};
ecx.instantiate_normalizes_to_term(goal, error_term);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
};
if !assoc_def.item.defaultness(tcx).has_value() {
return error_response(ecx, "missing value for assoc item in impl");
if !tcx.has_item_definition(target_item_def_id) {
return error_response(ecx, "missing item");
}
let target_container_def_id = tcx.parent(target_item_def_id);
// Getting the right args here is complex, e.g. given:
// - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>`
// - the applicable impl `impl<T> Trait<i32> for Vec<T>`
@ -223,39 +220,40 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
//
// And then map these args to the args of the defining impl of `Assoc`, going
// from `[u32, u64]` to `[u32, i32, u64]`.
let associated_item_args =
ecx.translate_args(&assoc_def, goal, impl_def_id, impl_args, impl_trait_ref)?;
let target_args = ecx.translate_args(
goal,
impl_def_id,
impl_args,
impl_trait_ref,
target_container_def_id,
)?;
if !tcx.check_args_compatible(assoc_def.item.def_id, associated_item_args) {
return error_response(
ecx,
"associated item has mismatched generic item arguments",
);
if !tcx.check_args_compatible(target_item_def_id, target_args) {
return error_response(ecx, "associated item has mismatched arguments");
}
// Finally we construct the actual value of the associated type.
let term = match goal.predicate.alias.kind(tcx) {
ty::AliasTermKind::ProjectionTy => {
tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into())
tcx.type_of(target_item_def_id).map_bound(|ty| ty.into())
}
ty::AliasTermKind::ProjectionConst => {
if tcx.features().associated_const_equality {
bug!("associated const projection is not supported yet")
if tcx.features().associated_const_equality() {
panic!("associated const projection is not supported yet")
} else {
ty::EarlyBinder::bind(
ty::Const::new_error_with_message(
Const::new_error_with_message(
tcx,
DUMMY_SP,
"associated const projection is not supported yet",
)
.into(),
)
}
}
kind => bug!("expected projection, found {kind:?}"),
kind => panic!("expected projection, found {kind:?}"),
};
ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args));
ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, &target_args));
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
@ -263,63 +261,60 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
/// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error`
/// and succeed. Can experiment with this to figure out what results in better error messages.
fn consider_error_guaranteed_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
_guar: ErrorGuaranteed,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
_ecx: &mut EvalCtxt<'_, Infcx>,
_guar: I::ErrorGuaranteed,
) -> Result<Candidate<I>, NoSolution> {
Err(NoSolution)
}
fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx.interner().dcx().span_delayed_bug(
ecx.interner().def_span(goal.predicate.def_id()),
"associated types not allowed on auto traits",
);
ecx: &mut EvalCtxt<'_, Infcx>,
_goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
ecx.interner().delay_bug("associated types not allowed on auto traits");
Err(NoSolution)
}
fn consider_trait_alias_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("trait aliases do not have associated types: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("trait aliases do not have associated types: {:?}", goal);
}
fn consider_builtin_sized_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("`Sized` does not have an associated type: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("`Sized` does not have an associated type: {:?}", goal);
}
fn consider_builtin_copy_clone_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
}
fn consider_builtin_pointer_like_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("`PointerLike` does not have an associated type: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("`PointerLike` does not have an associated type: {:?}", goal);
}
fn consider_builtin_fn_ptr_trait_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("`FnPtr` does not have an associated type: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("`FnPtr` does not have an associated type: {:?}", goal);
}
fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
goal_kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner();
let tupled_inputs_and_output =
match structural_traits::extract_tupled_inputs_and_output_from_callable(
@ -333,7 +328,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
};
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output])
ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output])
});
let pred = tupled_inputs_and_output
@ -359,16 +354,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_async_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
goal_kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner();
let env_region = match goal_kind {
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2),
// Doesn't matter what this region is
ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
ty::ClosureKind::FnOnce => Region::new_static(tcx),
};
let (tupled_inputs_and_output_and_coroutine, nested_preds) =
structural_traits::extract_tupled_inputs_and_output_from_async_callable(
@ -379,7 +374,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
)?;
let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
|AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| {
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output_ty])
ty::TraitRef::new(
tcx,
tcx.require_lang_item(TraitSolverLangItem::Sized),
[output_ty],
)
},
);
@ -391,7 +390,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
coroutine_return_ty,
}| {
let (projection_term, term) = if tcx
.is_lang_item(goal.predicate.def_id(), LangItem::CallOnceFuture)
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallOnceFuture)
{
(
ty::AliasTerm::new(
@ -401,34 +400,41 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
),
output_coroutine_ty.into(),
)
} else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CallRefFuture) {
(
ty::AliasTerm::new(
tcx,
goal.predicate.def_id(),
[
ty::GenericArg::from(goal.predicate.self_ty()),
tupled_inputs_ty.into(),
env_region.into(),
],
),
output_coroutine_ty.into(),
)
} else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::AsyncFnOnceOutput)
} else if tcx
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallRefFuture)
{
(
ty::AliasTerm::new(
tcx,
goal.predicate.def_id(),
[
ty::GenericArg::from(goal.predicate.self_ty()),
I::GenericArg::from(goal.predicate.self_ty()),
tupled_inputs_ty.into(),
env_region.into(),
],
),
output_coroutine_ty.into(),
)
} else if tcx.is_lang_item(
goal.predicate.def_id(),
TraitSolverLangItem::AsyncFnOnceOutput,
) {
(
ty::AliasTerm::new(
tcx,
goal.predicate.def_id(),
[
I::GenericArg::from(goal.predicate.self_ty()),
tupled_inputs_ty.into(),
],
),
coroutine_return_ty.into(),
)
} else {
bug!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id())
panic!(
"no such associated type in `AsyncFn*`: {:?}",
goal.predicate.def_id()
)
};
ty::ProjectionPredicate { projection_term, term }
},
@ -450,9 +456,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_async_fn_kind_helper_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let [
closure_fn_kind_ty,
goal_kind_ty,
@ -462,7 +468,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
coroutine_captures_by_ref_ty,
] = **goal.predicate.alias.args
else {
bug!();
panic!();
};
// Bail if the upvars haven't been constrained.
@ -497,18 +503,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_tuple_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("`Tuple` does not have an associated type: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("`Tuple` does not have an associated type: {:?}", goal);
}
fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner();
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
let metadata_def_id = tcx.require_lang_item(TraitSolverLangItem::Metadata);
assert_eq!(metadata_def_id, goal.predicate.def_id());
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
let metadata_ty = match goal.predicate.self_ty().kind() {
@ -530,16 +536,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
| ty::CoroutineWitness(..)
| ty::Never
| ty::Foreign(..)
| ty::Dynamic(_, _, ty::DynStar) => tcx.types.unit,
| ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(tcx),
ty::Error(e) => Ty::new_error(tcx, *e),
ty::Error(e) => Ty::new_error(tcx, e),
ty::Str | ty::Slice(_) => tcx.types.usize,
ty::Str | ty::Slice(_) => Ty::new_usize(tcx),
ty::Dynamic(_, _, ty::Dyn) => {
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
let dyn_metadata = tcx.require_lang_item(TraitSolverLangItem::DynMetadata);
tcx.type_of(dyn_metadata)
.instantiate(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
.instantiate(tcx, &[I::GenericArg::from(goal.predicate.self_ty())])
}
ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
@ -549,32 +555,31 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
// exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
let sized_predicate = ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::Sized, None),
[ty::GenericArg::from(goal.predicate.self_ty())],
tcx.require_lang_item(TraitSolverLangItem::Sized),
[I::GenericArg::from(goal.predicate.self_ty())],
);
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate));
tcx.types.unit
Ty::new_unit(tcx)
}
ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
None => tcx.types.unit,
Some(tail_def) => {
let tail_ty = tail_def.ty(tcx, args);
Ty::new_projection(tcx, metadata_def_id, [tail_ty])
ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(tcx) {
None => Ty::new_unit(tcx),
Some(tail_ty) => {
Ty::new_projection(tcx, metadata_def_id, [tail_ty.instantiate(tcx, &args)])
}
},
ty::Adt(_, _) => tcx.types.unit,
ty::Adt(_, _) => Ty::new_unit(tcx),
ty::Tuple(elements) => match elements.last() {
None => tcx.types.unit,
None => Ty::new_unit(tcx),
Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]),
},
ty::Infer(
ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
)
| ty::Bound(..) => bug!(
| ty::Bound(..) => panic!(
"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
goal.predicate.self_ty()
),
@ -586,11 +591,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty();
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
let ty::Coroutine(def_id, args) = self_ty.kind() else {
return Err(NoSolution);
};
@ -622,11 +627,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty();
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
let ty::Coroutine(def_id, args) = self_ty.kind() else {
return Err(NoSolution);
};
@ -658,18 +663,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_fused_iterator_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("`FusedIterator` does not have an associated type: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("`FusedIterator` does not have an associated type: {:?}", goal);
}
fn consider_builtin_async_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty();
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
let ty::Coroutine(def_id, args) = self_ty.kind() else {
return Err(NoSolution);
};
@ -685,10 +690,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
// coroutine yield ty `Poll<Option<I>>`.
let wrapped_expected_ty = Ty::new_adt(
tcx,
tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)),
tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Poll)),
tcx.mk_args(&[Ty::new_adt(
tcx,
tcx.adt_def(tcx.require_lang_item(LangItem::Option, None)),
tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Option)),
tcx.mk_args(&[expected_ty.into()]),
)
.into()]),
@ -701,11 +706,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty();
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
let ty::Coroutine(def_id, args) = self_ty.kind() else {
return Err(NoSolution);
};
@ -717,15 +722,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
let coroutine = args.as_coroutine();
let term = if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineReturn) {
let term = if tcx
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineReturn)
{
coroutine.return_ty().into()
} else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineYield) {
} else if tcx.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineYield) {
coroutine.yield_ty().into()
} else {
bug!(
"unexpected associated item `<{self_ty} as Coroutine>::{}`",
tcx.item_name(goal.predicate.def_id())
)
panic!("unexpected associated item `{:?}` for `{self_ty:?}`", goal.predicate.def_id())
};
Self::probe_and_consider_implied_clause(
@ -748,18 +752,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_structural_builtin_unsize_candidates(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Vec<Candidate<TyCtxt<'tcx>>> {
bug!("`Unsize` does not have an associated type: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Vec<Candidate<I>> {
panic!("`Unsize` does not have an associated type: {:?}", goal);
}
fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty();
let discriminant_ty = match *self_ty.kind() {
let discriminant_ty = match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(..)
@ -794,7 +798,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!(
| ty::Bound(..) => panic!(
"unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`",
goal.predicate.self_ty()
),
@ -807,11 +811,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_async_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty();
let async_destructor_ty = match *self_ty.kind() {
let async_destructor_ty = match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(..)
@ -842,12 +846,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Foreign(..)
| ty::Bound(..) => bug!(
| ty::Bound(..) => panic!(
"unexpected self ty `{:?}` when normalizing `<T as AsyncDestruct>::AsyncDestructor`",
goal.predicate.self_ty()
),
ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => bug!(
ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => panic!(
"`consider_builtin_async_destruct_candidate` is not yet implemented for type: {self_ty:?}"
),
};
@ -860,93 +864,56 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
}
fn consider_builtin_destruct_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("`Destruct` does not have an associated type: {:?}", goal);
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("`Destruct` does not have an associated type: {:?}", goal);
}
fn consider_builtin_transmute_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
_ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
}
}
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
fn translate_args(
&mut self,
assoc_def: &LeafDef,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
impl_def_id: DefId,
impl_args: ty::GenericArgsRef<'tcx>,
impl_trait_ref: rustc_type_ir::TraitRef<TyCtxt<'tcx>>,
) -> Result<ty::GenericArgsRef<'tcx>, NoSolution> {
goal: Goal<I, ty::NormalizesTo<I>>,
impl_def_id: I::DefId,
impl_args: I::GenericArgs,
impl_trait_ref: rustc_type_ir::TraitRef<I>,
target_container_def_id: I::DefId,
) -> Result<I::GenericArgs, NoSolution> {
let tcx = self.interner();
Ok(match assoc_def.defining_node {
Node::Trait(_) => goal.predicate.alias.args,
Node::Impl(target_impl_def_id) => {
if target_impl_def_id == impl_def_id {
Ok(if target_container_def_id == impl_trait_ref.def_id {
// Default value from the trait definition. No need to rebase.
goal.predicate.alias.args
} else if target_container_def_id == impl_def_id {
// Same impl, no need to fully translate, just a rebase from
// the trait is sufficient.
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args)
} else {
let target_args = self.fresh_args_for_item(target_impl_def_id);
let target_trait_ref = tcx
.impl_trait_ref(target_impl_def_id)
.unwrap()
.instantiate(tcx, target_args);
let target_args = self.fresh_args_for_item(target_container_def_id);
let target_trait_ref =
tcx.impl_trait_ref(target_container_def_id).instantiate(tcx, &target_args);
// Relate source impl to target impl by equating trait refs.
self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?;
// Also add predicates since they may be needed to constrain the
// target impl's params.
self.add_goals(
GoalSource::Misc,
tcx.predicates_of(target_impl_def_id)
.instantiate(tcx, target_args)
.into_iter()
.map(|(pred, _)| goal.with(tcx, pred)),
tcx.predicates_of(target_container_def_id)
.iter_instantiated(tcx, &target_args)
.map(|pred| goal.with(tcx, pred)),
);
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args)
}
}
})
}
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
///
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
/// diverge.
#[instrument(level = "trace", skip(self, param_env), ret)]
fn fetch_eligible_assoc_item_def(
&self,
param_env: ty::ParamEnv<'tcx>,
goal_trait_ref: ty::TraitRef<'tcx>,
trait_assoc_def_id: DefId,
impl_def_id: DefId,
) -> Result<Option<LeafDef>, NoSolution> {
let node_item =
specialization_graph::assoc_def(self.interner(), impl_def_id, trait_assoc_def_id)
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
let eligible = if node_item.is_final() {
// Non-specializable items are always projectable.
true
} else {
// Only reveal a specializable default if we're past type-checking
// and the obligation is monomorphic, otherwise passes such as
// transmute checking and polymorphic MIR optimizations could
// get a result which isn't correct for all monomorphizations.
if param_env.reveal() == Reveal::All {
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
!poly_trait_ref.still_further_specializable()
} else {
trace!(?node_item.item.def_id, "not eligible due to default");
false
}
};
if eligible { Ok(Some(node_item)) } else { Ok(None) }
}
}

View File

@ -2,20 +2,22 @@
//! behaves differently depending on the param-env's reveal mode and whether
//! the opaque is in a defining scope.
use crate::solve::infcx::SolverDelegate;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::traits::Reveal;
use rustc_middle::ty;
use rustc_middle::ty::util::NotUniqueParam;
use rustc_index::bit_set::GrowableBitSet;
use rustc_type_ir::inherent::*;
use rustc_type_ir::{self as ty, Interner};
use crate::solve::{EvalCtxt, SolverMode};
use crate::infcx::SolverDelegate;
use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode};
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
pub(super) fn normalize_opaque_type(
&mut self,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, ty::NormalizesTo<I>>,
) -> QueryResult<I> {
let tcx = self.interner();
let opaque_ty = goal.predicate.alias;
let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const");
@ -32,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
return Err(NoSolution);
}
// FIXME: This may have issues when the args contain aliases...
match self.interner().uses_unique_placeholders_ignoring_regions(opaque_ty.args) {
match uses_unique_placeholders_ignoring_regions(self.interner(), opaque_ty.args) {
Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
return self.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
@ -61,6 +63,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
}
// Otherwise, define a new opaque type
// FIXME: should we use `inject_hidden_type_unchecked` here?
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
self.add_item_bounds_for_hidden_type(
opaque_ty.def_id,
@ -83,10 +86,51 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
}
(Reveal::All, _) => {
// FIXME: Add an assertion that opaque type storage is empty.
let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args);
let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, &opaque_ty.args);
self.eq(goal.param_env, expected, actual)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}
}
}
/// Checks whether each generic argument is simply a unique generic placeholder.
///
/// FIXME: Interner argument is needed to constrain the `I` parameter.
pub fn uses_unique_placeholders_ignoring_regions<I: Interner>(
_interner: I,
args: I::GenericArgs,
) -> Result<(), NotUniqueParam<I>> {
let mut seen = GrowableBitSet::default();
for arg in args {
match arg.kind() {
// Ignore regions, since we can't resolve those in a canonicalized
// query in the trait solver.
ty::GenericArgKind::Lifetime(_) => {}
ty::GenericArgKind::Type(t) => match t.kind() {
ty::Placeholder(p) => {
if !seen.insert(p.var()) {
return Err(NotUniqueParam::DuplicateParam(t.into()));
}
}
_ => return Err(NotUniqueParam::NotParam(t.into())),
},
ty::GenericArgKind::Const(c) => match c.kind() {
ty::ConstKind::Placeholder(p) => {
if !seen.insert(p.var()) {
return Err(NotUniqueParam::DuplicateParam(c.into()));
}
}
_ => return Err(NotUniqueParam::NotParam(c.into())),
},
}
}
Ok(())
}
// FIXME: This should check for dupes and non-params first, then infer vars.
pub enum NotUniqueParam<I: Interner> {
DuplicateParam(I::GenericArg),
NotParam(I::GenericArg),
}

View File

@ -4,17 +4,20 @@
//! Since a weak alias is never ambiguous, this just computes the `type_of` of
//! the alias and registers the where-clauses of the type alias.
use crate::solve::infcx::SolverDelegate;
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
use rustc_middle::ty;
use rustc_type_ir::{self as ty, Interner};
use crate::solve::EvalCtxt;
use crate::infcx::SolverDelegate;
use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult};
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
pub(super) fn normalize_weak_type(
&mut self,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, ty::NormalizesTo<I>>,
) -> QueryResult<I> {
let tcx = self.interner();
let weak_ty = goal.predicate.alias;
@ -22,13 +25,11 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
self.add_goals(
GoalSource::Misc,
tcx.predicates_of(weak_ty.def_id)
.instantiate(tcx, weak_ty.args)
.predicates
.into_iter()
.iter_instantiated(tcx, &weak_ty.args)
.map(|pred| goal.with(tcx, pred)),
);
let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args);
let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, &weak_ty.args);
self.instantiate_normalizes_to_term(goal, actual.into());
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)

View File

@ -1,16 +1,18 @@
use crate::solve::GoalSource;
use rustc_type_ir::{self as ty, Interner, ProjectionPredicate};
use super::infcx::SolverDelegate;
use super::EvalCtxt;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty::{self, ProjectionPredicate};
use crate::infcx::SolverDelegate;
use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult};
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "trace", skip(self), ret)]
pub(super) fn compute_projection_goal(
&mut self,
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, ProjectionPredicate<I>>,
) -> QueryResult<I> {
let tcx = self.interner();
let projection_term = goal.predicate.projection_term.to_term(tcx);
let goal = goal.with(

View File

@ -1,19 +1,18 @@
use std::mem;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_index::Idx;
use rustc_index::IndexVec;
use rustc_next_trait_solver::infcx::SolverDelegate;
use rustc_next_trait_solver::solve::CacheData;
use rustc_next_trait_solver::solve::{CanonicalInput, Certainty, QueryResult};
use rustc_session::Limit;
use rustc_index::{Idx, IndexVec};
use rustc_type_ir::inherent::*;
use rustc_type_ir::Interner;
use super::inspect;
use super::inspect::ProofTreeBuilder;
use super::SolverMode;
use crate::solve::FIXPOINT_STEP_LIMIT;
use crate::infcx::SolverDelegate;
use crate::solve::inspect::{self, ProofTreeBuilder};
use crate::solve::{
CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT,
};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Limit(usize);
rustc_index::newtype_index! {
#[orderable]

View File

@ -1,60 +1,59 @@
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
use super::assembly::{self, structural_traits, Candidate};
use super::infcx::SolverDelegate;
use super::{EvalCtxt, GoalSource, SolverMode};
use rustc_ast_ir::Movability;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId;
use rustc_hir::{LangItem, Movability};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::solve::MaybeCause;
use rustc_infer::traits::util::supertraits;
use rustc_middle::bug;
use rustc_middle::traits::solve::inspect::ProbeKind;
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
use rustc_middle::traits::{BuiltinImplSource, Reveal};
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
use rustc_span::ErrorGuaranteed;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_type_ir::visit::TypeVisitableExt as _;
use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _};
impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
fn self_ty(self) -> Ty<'tcx> {
use crate::infcx::SolverDelegate;
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
use crate::solve::assembly::{self, Candidate};
use crate::solve::inspect::ProbeKind;
use crate::solve::{
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
NoSolution, QueryResult, Reveal, SolverMode,
};
impl<Infcx, I> assembly::GoalKind<Infcx> for TraitPredicate<I>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
fn self_ty(self) -> I::Ty {
self.self_ty()
}
fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
fn trait_ref(self, _: I) -> ty::TraitRef<I> {
self.trait_ref
}
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self {
self.with_self_ty(tcx, self_ty)
}
fn trait_def_id(self, _: TyCtxt<'tcx>) -> DefId {
fn trait_def_id(self, _: I) -> I::DefId {
self.def_id()
}
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, TraitPredicate<'tcx>>,
impl_def_id: DefId,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, TraitPredicate<I>>,
impl_def_id: I::DefId,
) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner();
let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
if !drcx.args_may_unify(
goal.predicate.trait_ref.args,
impl_trait_header.trait_ref.skip_binder().args,
) {
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
if !tcx
.args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
{
return Err(NoSolution);
}
// An upper bound of the certainty of this goal, used to lower the certainty
// of reservation impl to ambiguous during coherence.
let impl_polarity = impl_trait_header.polarity;
let impl_polarity = tcx.impl_polarity(impl_def_id);
let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
// In intercrate mode, this is ambiguous. But outside of intercrate,
// it's not a real impl.
@ -77,14 +76,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
let impl_args = ecx.fresh_args_for_item(impl_def_id);
ecx.record_impl_args(impl_args);
let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args);
let impl_trait_ref = impl_trait_ref.instantiate(tcx, &impl_args);
ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
let where_clause_bounds = tcx
.predicates_of(impl_def_id)
.instantiate(tcx, impl_args)
.predicates
.into_iter()
.iter_instantiated(tcx, &impl_args)
.map(|pred| goal.with(tcx, pred));
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
@ -93,21 +90,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_error_guaranteed_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
_guar: ErrorGuaranteed,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
_guar: I::ErrorGuaranteed,
) -> Result<Candidate<I>, NoSolution> {
// FIXME: don't need to enter a probe here.
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
}
fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
source: CandidateSource<'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Clause<'tcx>,
then: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>) -> QueryResult<'tcx>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
source: CandidateSource<I>,
goal: Goal<I, Self>,
assumption: I::Clause,
then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
) -> Result<Candidate<I>, NoSolution> {
if let Some(trait_clause) = assumption.as_trait_clause() {
if trait_clause.def_id() == goal.predicate.def_id()
&& trait_clause.polarity() == goal.predicate.polarity
@ -130,9 +127,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -159,7 +156,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
if matches!(goal.param_env.reveal(), Reveal::All)
|| matches!(ecx.solver_mode(), SolverMode::Coherence)
|| ecx.can_define_opaque_ty(opaque_ty.def_id)
|| opaque_ty
.def_id
.as_local()
.is_some_and(|def_id| ecx.can_define_opaque_ty(def_id))
{
return Err(NoSolution);
}
@ -173,9 +173,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_trait_alias_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -185,20 +185,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
let nested_obligations = tcx
.predicates_of(goal.predicate.def_id())
.instantiate(tcx, goal.predicate.trait_ref.args);
.iter_instantiated(tcx, &goal.predicate.trait_ref.args)
.map(|p| goal.with(tcx, p));
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
ecx.add_goals(
GoalSource::Misc,
nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)),
);
ecx.add_goals(GoalSource::Misc, nested_obligations);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
fn consider_builtin_sized_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -211,9 +209,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_copy_clone_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -226,28 +224,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
// The regions of a type don't affect the size of the type
let tcx = ecx.interner();
// We should erase regions from both the param-env and type, since both
// may have infer regions. Specifically, after canonicalizing and instantiating,
// early bound regions turn into region vars in both the new and old solver.
let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty()));
// But if there are inference variables, we have to wait until it's resolved.
if key.has_non_region_infer() {
if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() {
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
}
if let Ok(layout) = tcx.layout_of(key)
&& layout.layout.is_pointer_like(&tcx.data_layout)
{
// FIXME: We could make this faster by making a no-constraints response
if tcx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) {
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
} else {
@ -256,9 +246,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_fn_ptr_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty();
match goal.predicate.polarity {
// impl FnPtr for FnPtr {}
@ -287,10 +277,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
goal_kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -308,7 +298,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
};
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output])
ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output])
});
let pred = tupled_inputs_and_output
@ -328,10 +318,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_async_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
goal_kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -343,13 +333,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
goal.predicate.self_ty(),
goal_kind,
// This region doesn't matter because we're throwing away the coroutine type
tcx.lifetimes.re_static,
Region::new_static(tcx),
)?;
let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
|AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::Sized, None),
tcx.require_lang_item(TraitSolverLangItem::Sized),
[output_coroutine_ty],
)
},
@ -379,11 +369,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_async_fn_kind_helper_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else {
bug!();
panic!();
};
let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
@ -406,9 +396,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
/// impl Tuple for (T1, .., Tn) {}
/// ```
fn consider_builtin_tuple_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -422,9 +412,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -434,14 +424,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
return Err(NoSolution);
};
@ -460,14 +450,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
return Err(NoSolution);
};
@ -486,14 +476,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_fused_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
return Err(NoSolution);
};
@ -510,14 +500,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_async_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
return Err(NoSolution);
};
@ -536,15 +526,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
let self_ty = goal.predicate.self_ty();
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
let ty::Coroutine(def_id, args) = self_ty.kind() else {
return Err(NoSolution);
};
@ -568,9 +558,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -581,9 +571,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_async_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -594,9 +584,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -610,10 +600,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
fn consider_builtin_transmute_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
_ecx: &mut EvalCtxt<'_, Infcx>,
_goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
// TODO:
todo!()
/* if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@ -641,6 +633,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
)?;
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
})
*/
}
/// ```ignore (builtin impl example)
@ -651,9 +644,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
/// impl<'a, T: Trait + 'a> Unsize<dyn Trait + 'a> for T {}
/// ```
fn consider_structural_builtin_unsize_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
goal: Goal<'tcx, Self>,
) -> Vec<Candidate<TyCtxt<'tcx>>> {
ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<I, Self>,
) -> Vec<Candidate<I>> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return vec![];
}
@ -676,7 +669,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let goal = goal.with(ecx.interner(), (a_ty, b_ty));
match (a_ty.kind(), b_ty.kind()) {
(ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"),
(ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
(_, ty::Infer(ty::TyVar(..))) => {
result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
@ -684,24 +677,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
(
&ty::Dynamic(a_data, a_region, ty::Dyn),
&ty::Dynamic(b_data, b_region, ty::Dyn),
ty::Dynamic(a_data, a_region, ty::Dyn),
ty::Dynamic(b_data, b_region, ty::Dyn),
) => ecx.consider_builtin_dyn_upcast_candidates(
goal, a_data, a_region, b_data, b_region,
),
// `T` -> `dyn Trait` unsizing.
(_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
(_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
),
// `[T; N]` -> `[T]` unsizing
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
(ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
}
// `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))
if a_def.is_struct() && a_def == b_def =>
{
result_to_single(
@ -710,7 +703,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
// `(A, B, T)` -> `(A, B, U)` where `T: Unsize<U>`
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
(ty::Tuple(a_tys), ty::Tuple(b_tys))
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
{
result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys))
@ -722,7 +715,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
}
}
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
/// Trait upcasting allows for coercions between trait objects:
/// ```ignore (builtin impl example)
/// trait Super {}
@ -734,12 +731,12 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// ```
fn consider_builtin_dyn_upcast_candidates(
&mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
a_region: ty::Region<'tcx>,
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
b_region: ty::Region<'tcx>,
) -> Vec<Candidate<TyCtxt<'tcx>>> {
goal: Goal<I, (I::Ty, I::Ty)>,
a_data: I::BoundExistentialPredicates,
a_region: I::Region,
b_data: I::BoundExistentialPredicates,
b_region: I::Region,
) -> Vec<Candidate<I>> {
let tcx = self.interner();
let Goal { predicate: (a_ty, _b_ty), .. } = goal;
@ -757,7 +754,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
a_data.principal(),
));
} else if let Some(a_principal) = a_data.principal() {
for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) {
for new_a_principal in
Infcx::elaborate_supertraits(self.interner(), a_principal.with_self_ty(tcx, a_ty))
.skip(1)
{
responses.extend(self.consider_builtin_upcast_to_principal(
goal,
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
@ -777,15 +777,15 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
fn consider_builtin_unsize_to_dyn_candidate(
&mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
b_region: ty::Region<'tcx>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
goal: Goal<I, (I::Ty, I::Ty)>,
b_data: I::BoundExistentialPredicates,
b_region: I::Region,
) -> Result<Candidate<I>, NoSolution> {
let tcx = self.interner();
let Goal { predicate: (a_ty, _), .. } = goal;
// Can only unsize to an object-safe trait.
if b_data.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) {
if b_data.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) {
return Err(NoSolution);
}
@ -794,7 +794,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// (i.e. the principal, all of the associated types match, and any auto traits)
ecx.add_goals(
GoalSource::ImplWhereBound,
b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
b_data.into_iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
);
// The type must be `Sized` to be unsized.
@ -802,7 +802,11 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
GoalSource::ImplWhereBound,
goal.with(
tcx,
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [a_ty]),
ty::TraitRef::new(
tcx,
tcx.require_lang_item(TraitSolverLangItem::Sized),
[a_ty],
),
),
);
@ -814,24 +818,26 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
fn consider_builtin_upcast_to_principal(
&mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
source: CandidateSource<'tcx>,
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
a_region: ty::Region<'tcx>,
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
b_region: ty::Region<'tcx>,
upcast_principal: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
goal: Goal<I, (I::Ty, I::Ty)>,
source: CandidateSource<I>,
a_data: I::BoundExistentialPredicates,
a_region: I::Region,
b_data: I::BoundExistentialPredicates,
b_region: I::Region,
upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
) -> Result<Candidate<I>, NoSolution> {
let param_env = goal.param_env;
// We may upcast to auto traits that are either explicitly listed in
// the object type's bounds, or implied by the principal trait ref's
// supertraits.
let a_auto_traits: FxIndexSet<DefId> = a_data
let a_auto_traits: FxIndexSet<I::DefId> = a_data
.auto_traits()
.into_iter()
.chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
self.interner()
.supertrait_def_ids(principal_def_id)
.into_iter()
.filter(|def_id| self.interner().trait_is_auto(*def_id))
}))
.collect();
@ -841,9 +847,9 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// having any inference side-effects. We process obligations because
// unification may initially succeed due to deferred projection equality.
let projection_may_match =
|ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>,
source_projection: ty::PolyExistentialProjection<'tcx>,
target_projection: ty::PolyExistentialProjection<'tcx>| {
|ecx: &mut EvalCtxt<'_, Infcx>,
source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
source_projection.item_def_id() == target_projection.item_def_id()
&& ecx
.probe(|_| ProbeKind::UpcastProjectionCompatibility)
@ -875,7 +881,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
ty::ExistentialPredicate::Projection(target_projection) => {
let target_projection = bound.rebind(target_projection);
let mut matching_projections =
a_data.projection_bounds().filter(|source_projection| {
a_data.projection_bounds().into_iter().filter(|source_projection| {
projection_may_match(ecx, *source_projection, target_projection)
});
let Some(source_projection) = matching_projections.next() else {
@ -900,11 +906,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// Also require that a_ty's lifetime outlives b_ty's lifetime.
ecx.add_goal(
GoalSource::ImplWhereBound,
Goal::new(
ecx.interner(),
param_env,
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
),
Goal::new(ecx.interner(), param_env, ty::OutlivesPredicate(a_region, b_region)),
);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
@ -921,10 +923,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// `#[rustc_deny_explicit_impl]` in this case.
fn consider_builtin_array_unsize(
&mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
a_elem_ty: Ty<'tcx>,
b_elem_ty: Ty<'tcx>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
goal: Goal<I, (I::Ty, I::Ty)>,
a_elem_ty: I::Ty,
b_elem_ty: I::Ty,
) -> Result<Candidate<I>, NoSolution> {
self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
@ -945,26 +947,25 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// ```
fn consider_builtin_struct_unsize(
&mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
def: ty::AdtDef<'tcx>,
a_args: ty::GenericArgsRef<'tcx>,
b_args: ty::GenericArgsRef<'tcx>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
goal: Goal<I, (I::Ty, I::Ty)>,
def: I::AdtDef,
a_args: I::GenericArgs,
b_args: I::GenericArgs,
) -> Result<Candidate<I>, NoSolution> {
let tcx = self.interner();
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
let unsizing_params = tcx.unsizing_params_for_adt(def.did());
let unsizing_params = tcx.unsizing_params_for_adt(def.def_id());
// We must be unsizing some type parameters. This also implies
// that the struct has a tail field.
if unsizing_params.is_empty() {
return Err(NoSolution);
}
let tail_field = def.non_enum_variant().tail();
let tail_field_ty = tcx.type_of(tail_field.did);
let tail_field_ty = def.struct_tail_ty(tcx).unwrap();
let a_tail_ty = tail_field_ty.instantiate(tcx, a_args);
let b_tail_ty = tail_field_ty.instantiate(tcx, b_args);
let a_tail_ty = tail_field_ty.instantiate(tcx, &a_args);
let b_tail_ty = tail_field_ty.instantiate(tcx, &b_args);
// Instantiate just the unsizing params from B into A. The type after
// this instantiation must be equal to B. This is so we don't unsize
@ -973,7 +974,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
a_args
.iter()
.enumerate()
.map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { a }),
.map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { *a }),
);
let unsized_a_ty = Ty::new_adt(tcx, def, new_a_args);
@ -986,7 +987,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
tcx,
ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::Unsize, None),
tcx.require_lang_item(TraitSolverLangItem::Unsize),
[a_tail_ty, b_tail_ty],
),
),
@ -1007,10 +1008,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// ```
fn consider_builtin_tuple_unsize(
&mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
a_tys: &'tcx ty::List<Ty<'tcx>>,
b_tys: &'tcx ty::List<Ty<'tcx>>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
goal: Goal<I, (I::Ty, I::Ty)>,
a_tys: I::Tys,
b_tys: I::Tys,
) -> Result<Candidate<I>, NoSolution> {
let tcx = self.interner();
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
@ -1029,7 +1030,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
tcx,
ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::Unsize, None),
tcx.require_lang_item(TraitSolverLangItem::Unsize),
[a_last_ty, b_last_ty],
),
),
@ -1044,10 +1045,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// the type's constituent types.
fn disqualify_auto_trait_candidate_due_to_possible_impl(
&mut self,
goal: Goal<'tcx, TraitPredicate<'tcx>>,
) -> Option<Result<Candidate<TyCtxt<'tcx>>, NoSolution>> {
goal: Goal<I, TraitPredicate<I>>,
) -> Option<Result<Candidate<I>, NoSolution>> {
let self_ty = goal.predicate.self_ty();
match *self_ty.kind() {
match self_ty.kind() {
// Stall int and float vars until they are resolved to a concrete
// numerical type. That's because the check for impls below treats
// int vars as matching any impl. Even if we filtered such impls,
@ -1065,13 +1066,15 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
| ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..)
| ty::Placeholder(..) => Some(Err(NoSolution)),
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
// Coroutines have one special built-in candidate, `Unpin`, which
// takes precedence over the structural auto trait candidate being
// assembled.
ty::Coroutine(def_id, _)
if self.interner().is_lang_item(goal.predicate.def_id(), LangItem::Unpin) =>
if self
.interner()
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
{
match self.interner().coroutine_movability(def_id) {
Movability::Static => Some(Err(NoSolution)),
@ -1144,13 +1147,13 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// wrapped in one.
fn probe_and_evaluate_goal_for_constituent_tys(
&mut self,
source: CandidateSource<'tcx>,
goal: Goal<'tcx, TraitPredicate<'tcx>>,
source: CandidateSource<I>,
goal: Goal<I, TraitPredicate<I>>,
constituent_tys: impl Fn(
&EvalCtxt<'_, SolverDelegate<'tcx>>,
Ty<'tcx>,
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
&EvalCtxt<'_, Infcx>,
I::Ty,
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>,
) -> Result<Candidate<I>, NoSolution> {
self.probe_trait_candidate(source).enter(|ecx| {
ecx.add_goals(
GoalSource::ImplWhereBound,
@ -1173,8 +1176,8 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
#[instrument(level = "trace", skip(self))]
pub(super) fn compute_trait_goal(
&mut self,
goal: Goal<'tcx, TraitPredicate<'tcx>>,
) -> QueryResult<'tcx> {
goal: Goal<I, TraitPredicate<I>>,
) -> QueryResult<I> {
let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_candidates(candidates)
}

View File

@ -1,7 +0,0 @@
pub use rustc_middle::traits::solve::inspect::*;
mod build;
pub(in crate::solve) use build::*;
mod analyse;
pub use analyse::*;

View File

@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
use crate::fold::{TypeFoldable, TypeSuperFoldable};
use crate::relate::Relate;
use crate::solve::{CacheData, CanonicalInput, QueryResult};
use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
@ -29,10 +29,14 @@ pub trait Ty<I: Interner<Ty = Self>>:
+ Relate<I>
+ Flags
{
fn new_unit(interner: I) -> Self;
fn new_bool(interner: I) -> Self;
fn new_u8(interner: I) -> Self;
fn new_usize(interner: I) -> Self;
fn new_infer(interner: I, var: ty::InferTy) -> Self;
fn new_var(interner: I, var: ty::TyVid) -> Self;
@ -109,6 +113,10 @@ pub trait Ty<I: Interner<Ty = Self>>:
matches!(self.kind(), ty::Infer(ty::TyVar(_)))
}
fn is_fn_ptr(self) -> bool {
matches!(self.kind(), ty::FnPtr(_))
}
fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
match self.kind() {
ty::FnPtr(sig) => sig,
@ -128,6 +136,49 @@ pub trait Ty<I: Interner<Ty = Self>>:
_ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self),
}
}
fn discriminant_ty(self, interner: I) -> I::Ty;
fn async_destructor_ty(self, interner: I) -> I::Ty;
/// Returns `true` when the outermost type cannot be further normalized,
/// resolved, or instantiated. This includes all primitive types, but also
/// things like ADTs and trait objects, sice even if their arguments or
/// nested types may be further simplified, the outermost [`ty::TyKind`] or
/// type constructor remains the same.
fn is_known_rigid(self) -> bool {
match self.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Adt(_, _)
| ty::Foreign(_)
| ty::Str
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::Slice(_)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(_)
| ty::Dynamic(_, _, _)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(..)
| ty::Never
| ty::Tuple(_) => true,
ty::Error(_)
| ty::Infer(_)
| ty::Alias(_, _)
| ty::Param(_)
| ty::Bound(_, _)
| ty::Placeholder(_) => false,
}
}
}
pub trait Tys<I: Interner<Tys = Self>>:
@ -202,6 +253,12 @@ pub trait Const<I: Interner<Const = Self>>:
fn new_expr(interner: I, expr: I::ExprConst) -> Self;
fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self;
fn new_error_with_message(interner: I, msg: impl ToString) -> Self {
Self::new_error(interner, interner.delay_bug(msg))
}
fn is_ct_var(self) -> bool {
matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_)))
}
@ -223,6 +280,37 @@ pub trait GenericArg<I: Interner<GenericArg = Self>>:
+ From<I::Region>
+ From<I::Const>
{
fn as_type(&self) -> Option<I::Ty> {
if let ty::GenericArgKind::Type(ty) = self.kind() { Some(ty) } else { None }
}
fn expect_ty(&self) -> I::Ty {
self.as_type().expect("expected a type")
}
fn as_const(&self) -> Option<I::Const> {
if let ty::GenericArgKind::Const(c) = self.kind() { Some(c) } else { None }
}
fn expect_const(&self) -> I::Const {
self.as_const().expect("expected a const")
}
fn as_region(&self) -> Option<I::Region> {
if let ty::GenericArgKind::Lifetime(c) = self.kind() { Some(c) } else { None }
}
fn expect_region(&self) -> I::Region {
self.as_region().expect("expected a const")
}
fn is_non_region_infer(self) -> bool {
match self.kind() {
ty::GenericArgKind::Lifetime(_) => false,
ty::GenericArgKind::Type(ty) => ty.is_ty_var(),
ty::GenericArgKind::Const(ct) => ct.is_ct_var(),
}
}
}
pub trait Term<I: Interner<Term = Self>>:
@ -232,7 +320,7 @@ pub trait Term<I: Interner<Term = Self>>:
if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None }
}
fn expect_type(&self) -> I::Ty {
fn expect_ty(&self) -> I::Ty {
self.as_type().expect("expected a type, but found a const")
}
@ -250,6 +338,19 @@ pub trait Term<I: Interner<Term = Self>>:
ty::TermKind::Const(ct) => ct.is_ct_var(),
}
}
fn to_alias_term(self) -> Option<ty::AliasTerm<I>> {
match self.kind() {
ty::TermKind::Ty(ty) => match ty.kind() {
ty::Alias(_kind, alias_ty) => Some(alias_ty.into()),
_ => None,
},
ty::TermKind::Const(ct) => match ct.kind() {
ty::ConstKind::Unevaluated(uv) => Some(uv.into()),
_ => None,
},
}
}
}
pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
@ -262,8 +363,17 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
+ Default
+ Relate<I>
{
fn rebase_onto(
self,
interner: I,
source_def_id: I::DefId,
target: I::GenericArgs,
) -> I::GenericArgs;
fn type_at(self, i: usize) -> I::Ty;
fn region_at(self, i: usize) -> I::Region;
fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs;
fn extend_with_error(
@ -303,6 +413,9 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
+ UpcastFrom<I, ty::NormalizesTo<I>>
+ UpcastFrom<I, ty::TraitRef<I>>
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+ UpcastFrom<I, ty::TraitPredicate<I>>
+ UpcastFrom<I, ty::OutlivesPredicate<I, I::Ty>>
+ UpcastFrom<I, ty::OutlivesPredicate<I, I::Region>>
+ IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
{
fn is_coinductive(self, interner: I) -> bool;
@ -318,9 +431,34 @@ pub trait Clause<I: Interner<Clause = Self>>:
+ Eq
+ TypeFoldable<I>
// FIXME: Remove these, uplift the `Upcast` impls.
+ UpcastFrom<I, ty::TraitRef<I>>
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+ UpcastFrom<I, ty::ProjectionPredicate<I>>
+ UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
+ IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
{
fn as_trait_clause(self) -> Option<ty::Binder<I, ty::TraitPredicate<I>>> {
self.kind()
.map_bound(|clause| {
if let ty::ClauseKind::Trait(t) = clause {
Some(t)
} else {
None
}
})
.transpose()
}
fn as_projection_clause(self) -> Option<ty::Binder<I, ty::ProjectionPredicate<I>>> {
self.kind()
.map_bound(|clause| {
if let ty::ClauseKind::Projection(p) = clause {
Some(p)
} else {
None
}
})
.transpose()
}
}
/// Common capabilities of placeholder kinds
@ -352,18 +490,33 @@ pub trait ParamLike {
pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
fn def_id(self) -> I::DefId;
fn is_struct(self) -> bool;
/// Returns the type of the struct tail.
///
/// Expects the `AdtDef` to be a struct. If it is not, then this will panic.
fn struct_tail_ty(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
fn is_phantom_data(self) -> bool;
// FIXME: perhaps use `all_fields` and expose `FieldDef`.
fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl Iterator<Item = I::Ty>>;
fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl IntoIterator<Item = I::Ty>>;
fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
}
pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
fn reveal(self) -> Reveal;
fn caller_bounds(self) -> impl IntoIterator<Item = I::Clause>;
}
pub trait Features<I: Interner>: Copy {
fn generic_const_exprs(self) -> bool;
fn coroutine_clone(self) -> bool;
fn associated_const_equality(self) -> bool;
}
pub trait EvaluationCache<I: Interner> {
@ -392,3 +545,26 @@ pub trait EvaluationCache<I: Interner> {
available_depth: usize,
) -> Option<CacheData<I>>;
}
pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
fn as_local(self) -> Option<I::LocalDefId>;
}
pub trait BoundExistentialPredicates<I: Interner>:
Copy
+ Debug
+ Hash
+ Eq
+ Relate<I>
+ IntoIterator<Item = ty::Binder<I, ty::ExistentialPredicate<I>>>
{
fn principal_def_id(self) -> Option<I::DefId>;
fn principal(self) -> Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>;
fn auto_traits(self) -> impl IntoIterator<Item = I::DefId>;
fn projection_bounds(
self,
) -> impl IntoIterator<Item = ty::Binder<I, ty::ExistentialProjection<I>>>;
}

View File

@ -1,4 +1,5 @@
use rustc_ast_ir::Movability;
use rustc_index::bit_set::BitSet;
use smallvec::SmallVec;
use std::fmt::Debug;
use std::hash::Hash;
@ -10,7 +11,7 @@ use crate::ir_print::IrPrint;
use crate::lang_items::TraitSolverLangItem;
use crate::relate::Relate;
use crate::solve::inspect::CanonicalGoalEvaluationStep;
use crate::solve::{ExternalConstraintsData, SolverMode};
use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{self as ty};
@ -29,9 +30,8 @@ pub trait Interner:
+ IrPrint<ty::CoercePredicate<Self>>
+ IrPrint<ty::FnSig<Self>>
{
type DefId: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
type DefId: DefId<Self>;
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
type AdtDef: AdtDef<Self>;
type GenericArgs: GenericArgs<Self>;
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
@ -46,18 +46,45 @@ pub trait Interner:
+ Default;
type BoundVarKind: Copy + Debug + Hash + Eq;
type PredefinedOpaques: Copy + Debug + Hash + Eq;
type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
type PredefinedOpaques: Copy
+ Debug
+ Hash
+ Eq
+ TypeFoldable<Self>
+ Deref<Target = PredefinedOpaquesData<Self>>;
fn mk_predefined_opaques_in_body(
self,
data: PredefinedOpaquesData<Self>,
) -> Self::PredefinedOpaques;
type DefiningOpaqueTypes: Copy
+ Debug
+ Hash
+ Default
+ Eq
+ TypeVisitable<Self>
+ Deref<Target: Deref<Target = [Self::LocalDefId]>>;
type CanonicalGoalEvaluationStepRef: Copy
+ Debug
+ Hash
+ Eq
+ Deref<Target = CanonicalGoalEvaluationStep<Self>>;
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = ty::CanonicalVarInfo<Self>>;
type CanonicalVars: Copy
+ Debug
+ Hash
+ Eq
+ IntoIterator<Item = ty::CanonicalVarInfo<Self>>
+ Deref<Target: Deref<Target = [ty::CanonicalVarInfo<Self>]>>
+ Default;
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
type ExternalConstraints: Copy + Debug + Hash + Eq;
type ExternalConstraints: Copy
+ Debug
+ Hash
+ Eq
+ TypeFoldable<Self>
+ Deref<Target = ExternalConstraintsData<Self>>;
fn mk_external_constraints(
self,
data: ExternalConstraintsData<Self>,
@ -76,12 +103,7 @@ pub trait Interner:
// Things stored inside of tys
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
type BoundExistentialPredicates: Copy
+ Debug
+ Hash
+ Eq
+ Relate<Self>
+ IntoIterator<Item = ty::Binder<Self, ty::ExistentialPredicate<Self>>>;
type BoundExistentialPredicates: BoundExistentialPredicates<Self>;
type AllocId: Copy + Debug + Hash + Eq;
type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
type Safety: Safety<Self>;
@ -103,7 +125,7 @@ pub trait Interner:
type PlaceholderRegion: PlaceholderLike;
// Predicates
type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
type ParamEnv: ParamEnv<Self>;
type Predicate: Predicate<Self>;
type Clause: Clause<Self>;
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
@ -123,9 +145,11 @@ pub trait Interner:
+ IntoIterator<Item: Deref<Target = ty::Variance>>;
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf;
// FIXME: Remove after uplifting `EarlyBinder`
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
type AdtDef: AdtDef<Self>;
fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef;
fn alias_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind;
fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind;
@ -143,6 +167,8 @@ pub trait Interner:
I: Iterator<Item = T>,
T: CollectAndApply<Self::GenericArg, Self::GenericArgs>;
fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool;
fn check_and_mk_args(
self,
def_id: Self::DefId,
@ -187,6 +213,17 @@ pub trait Interner:
def_id: Self::DefId,
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
fn predicates_of(
self,
def_id: Self::DefId,
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
fn own_predicates_of(
self,
def_id: Self::DefId,
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
// FIXME: Rename this so it's obvious it's only *immediate* super predicates.
fn super_predicates_of(
self,
def_id: Self::DefId,
@ -196,7 +233,64 @@ pub trait Interner:
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId;
fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool;
fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
// FIXME: move `fast_reject` into `rustc_type_ir`.
fn args_may_unify_deep(
self,
obligation_args: Self::GenericArgs,
impl_args: Self::GenericArgs,
) -> bool;
fn for_each_relevant_impl(
self,
trait_def_id: Self::DefId,
self_ty: Self::Ty,
f: impl FnMut(Self::DefId),
);
fn has_item_definition(self, def_id: Self::DefId) -> bool;
fn impl_is_default(self, impl_def_id: Self::DefId) -> bool;
fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder<Self, ty::TraitRef<Self>>;
fn impl_polarity(self, impl_def_id: Self::DefId) -> ty::ImplPolarity;
fn trait_is_auto(self, trait_def_id: Self::DefId) -> bool;
fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool;
fn trait_is_object_safe(self, trait_def_id: Self::DefId) -> bool;
fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;
fn fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option<ty::ClosureKind>;
fn async_fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option<ty::ClosureKind>;
fn supertrait_def_ids(self, trait_def_id: Self::DefId)
-> impl IntoIterator<Item = Self::DefId>;
fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed;
fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool;
fn coroutine_is_async(self, coroutine_def_id: Self::DefId) -> bool;
fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool;
fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool;
fn layout_is_pointer_like(self, param_env: Self::ParamEnv, ty: Self::Ty) -> bool;
type UnsizingParams: Deref<Target = BitSet<u32>>;
fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
fn find_const_ty_from_env(
self,
param_env: Self::ParamEnv,
placeholder: Self::PlaceholderConst,
) -> Self::Ty;
}
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`

View File

@ -1,8 +1,36 @@
/// Lang items used by the new trait solver. This can be mapped to whatever internal
/// representation of `LangItem`s used in the underlying compiler implementation.
pub enum TraitSolverLangItem {
Future,
FutureOutput,
// tidy-alphabetical-start
AsyncDestruct,
AsyncFnKindHelper,
AsyncFnKindUpvars,
AsyncFnOnceOutput,
AsyncIterator,
CallOnceFuture,
CallRefFuture,
Clone,
Copy,
Coroutine,
CoroutineReturn,
CoroutineYield,
Destruct,
DiscriminantKind,
DynMetadata,
FnPtrTrait,
FusedIterator,
Future,
FutureOutput,
Iterator,
Metadata,
Option,
PointeeTrait,
PointerLike,
Poll,
Sized,
TransmuteTrait,
Tuple,
Unpin,
Unsize,
// tidy-alphabetical-end
}

View File

@ -7,7 +7,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
use crate::inherent::*;
use crate::lift::Lift;
use crate::upcast::Upcast;
use crate::upcast::{Upcast, UpcastFrom};
use crate::visit::TypeVisitableExt as _;
use crate::{self as ty, Interner};
@ -166,6 +166,12 @@ impl<I: Interner> ty::Binder<I, TraitPredicate<I>> {
}
}
impl<I: Interner> UpcastFrom<I, TraitRef<I>> for TraitPredicate<I> {
fn upcast_from(from: TraitRef<I>, _tcx: I) -> Self {
TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive }
}
}
impl<I: Interner> fmt::Debug for TraitPredicate<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// FIXME(effects) printing?