1
Fork 0

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" name = "rustc_next_trait_solver"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 2.5.0",
"derivative",
"rustc_ast_ir",
"rustc_data_structures",
"rustc_index",
"rustc_macros",
"rustc_serialize",
"rustc_type_ir", "rustc_type_ir",
"rustc_type_ir_macros",
"tracing",
] ]
[[package]] [[package]]

View file

@ -205,6 +205,14 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
self.did() 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 { fn is_phantom_data(self) -> bool {
self.is_phantom_data() self.is_phantom_data()
} }
@ -212,7 +220,7 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
fn all_field_tys( fn all_field_tys(
self, self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
) -> ty::EarlyBinder<'tcx, impl Iterator<Item = Ty<'tcx>>> { ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = Ty<'tcx>>> {
ty::EarlyBinder::bind( ty::EarlyBinder::bind(
self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()), 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 int::*;
pub use kind::*; pub use kind::*;
use rustc_span::Span;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use rustc_span::{ErrorGuaranteed, Span};
pub use valtree::*; pub use valtree::*;
pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>; 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 { fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self {
Const::new_expr(interner, expr) Const::new_expr(interner, expr)
} }
fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
Const::new_error(interner, guar)
}
} }
impl<'tcx> Const<'tcx> { impl<'tcx> Const<'tcx> {

View file

@ -90,46 +90,65 @@ use std::ops::{Bound, Deref};
impl<'tcx> Interner for TyCtxt<'tcx> { impl<'tcx> Interner for TyCtxt<'tcx> {
type DefId = DefId; type DefId = DefId;
type LocalDefId = LocalDefId; type LocalDefId = LocalDefId;
type AdtDef = ty::AdtDef<'tcx>;
type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>;
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
type GenericArg = ty::GenericArg<'tcx>; type GenericArg = ty::GenericArg<'tcx>;
type Term = ty::Term<'tcx>; type Term = ty::Term<'tcx>;
type BoundVarKinds = &'tcx List<ty::BoundVariableKind>; type BoundVarKinds = &'tcx List<ty::BoundVariableKind>;
type BoundVarKind = ty::BoundVariableKind;
type CanonicalVars = CanonicalVarInfos<'tcx>; type BoundVarKind = ty::BoundVariableKind;
type PredefinedOpaques = solve::PredefinedOpaques<'tcx>; 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 DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
type ExternalConstraints = ExternalConstraints<'tcx>;
type CanonicalGoalEvaluationStepRef = type CanonicalGoalEvaluationStepRef =
&'tcx solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>; &'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 Ty = Ty<'tcx>;
type Tys = &'tcx List<Ty<'tcx>>; type Tys = &'tcx List<Ty<'tcx>>;
type FnInputTys = &'tcx [Ty<'tcx>]; type FnInputTys = &'tcx [Ty<'tcx>];
type ParamTy = ParamTy; type ParamTy = ParamTy;
type BoundTy = ty::BoundTy; type BoundTy = ty::BoundTy;
type PlaceholderTy = ty::PlaceholderType;
type PlaceholderTy = ty::PlaceholderType;
type ErrorGuaranteed = ErrorGuaranteed; type ErrorGuaranteed = ErrorGuaranteed;
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>; type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
type AllocId = crate::mir::interpret::AllocId;
type AllocId = crate::mir::interpret::AllocId;
type Pat = Pattern<'tcx>; type Pat = Pattern<'tcx>;
type Safety = hir::Safety; type Safety = hir::Safety;
type Abi = abi::Abi; type Abi = abi::Abi;
type Const = ty::Const<'tcx>; type Const = ty::Const<'tcx>;
type PlaceholderConst = ty::PlaceholderConst; type PlaceholderConst = ty::PlaceholderConst;
type ParamConst = ty::ParamConst; type ParamConst = ty::ParamConst;
type BoundConst = ty::BoundVar; type BoundConst = ty::BoundVar;
type ValueConst = ty::ValTree<'tcx>; type ValueConst = ty::ValTree<'tcx>;
type ExprConst = ty::Expr<'tcx>; type ExprConst = ty::Expr<'tcx>;
type Region = Region<'tcx>; type Region = Region<'tcx>;
type EarlyParamRegion = ty::EarlyParamRegion; type EarlyParamRegion = ty::EarlyParamRegion;
type LateParamRegion = ty::LateParamRegion; type LateParamRegion = ty::LateParamRegion;
type BoundRegion = ty::BoundRegion; type BoundRegion = ty::BoundRegion;
@ -137,15 +156,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type ParamEnv = ty::ParamEnv<'tcx>; type ParamEnv = ty::ParamEnv<'tcx>;
type Predicate = Predicate<'tcx>; type Predicate = Predicate<'tcx>;
type Clause = Clause<'tcx>; type Clause = Clause<'tcx>;
type Clauses = ty::Clauses<'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>; type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>;
fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> { fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> {
match mode { match mode {
SolverMode::Normal => &self.new_solver_evaluation_cache, SolverMode::Normal => &self.new_solver_evaluation_cache,
@ -157,17 +173,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.expand_abstract_consts(t) 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; type GenericsOf = &'tcx ty::Generics;
fn generics_of(self, def_id: DefId) -> &'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) 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 { fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
match self.def_kind(alias.def_id) { match self.def_kind(alias.def_id) {
DefKind::AssocTy => { DefKind::AssocTy => {
@ -221,8 +231,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
fn trait_ref_and_own_args_for_alias( fn trait_ref_and_own_args_for_alias(
self, self,
def_id: DefId, def_id: DefId,
args: Self::GenericArgs, args: ty::GenericArgsRef<'tcx>,
) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) { ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
let trait_def_id = self.parent(def_id); let trait_def_id = self.parent(def_id);
assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); 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) self.mk_args(args)
} }
fn mk_args_from_iter<I, T>(self, args: I) -> T::Output fn mk_args_from_iter<I, T>(self, args: I) -> T::Output
where where
I: Iterator<Item = T>, I: Iterator<Item = T>,
T: CollectAndApply<Self::GenericArg, Self::GenericArgs>, T: CollectAndApply<Self::GenericArg, ty::GenericArgsRef<'tcx>>,
{ {
self.mk_args_from_iter(args) 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( fn check_and_mk_args(
self, self,
def_id: DefId, 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 fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
where where
I: Iterator<Item = T>, 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) 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) 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( fn super_predicates_of(
self, self,
def_id: DefId, def_id: DefId,
@ -326,15 +358,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
} }
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId { fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId {
self.require_lang_item( self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None)
match lang_item { }
TraitSolverLangItem::Future => hir::LangItem::Future,
TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput, fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool {
TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper, self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item))
TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars,
},
None,
)
} }
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> { 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)) .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
.map(|assoc_item| assoc_item.def_id) .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 { 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 { fn coroutine_clone(self) -> bool {
self.coroutine_clone self.coroutine_clone
} }
fn associated_const_equality(self) -> bool {
self.associated_const_equality
}
} }
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; 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::GenericArg<TyCtxt<'tcx>> for GenericArg<'tcx> {}
impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArgsRef<'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> { fn type_at(self, i: usize) -> Ty<'tcx> {
self.type_at(i) 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> { fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
GenericArgs::identity_for_item(tcx, def_id) GenericArgs::identity_for_item(tcx, def_id)
} }
@ -281,6 +294,7 @@ impl<'tcx> GenericArg<'tcx> {
pub fn is_non_region_infer(self) -> bool { pub fn is_non_region_infer(self) -> bool {
match self.unpack() { match self.unpack() {
GenericArgKind::Lifetime(_) => false, GenericArgKind::Lifetime(_) => false,
// FIXME: This shouldn't return numerical/float.
GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(), GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(),
GenericArgKind::Const(ct) => ct.is_ct_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) 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))] #[instrument(level = "debug", skip(self, tcx))]
fn instantiate_into( fn instantiate_into(
&self, &self,

View file

@ -990,6 +990,16 @@ pub struct ParamEnv<'tcx> {
packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>, 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)] #[derive(Copy, Clone)]
struct ParamTag { struct ParamTag {
reveal: traits::Reveal, 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::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> { impl<'tcx> Clause<'tcx> {
pub fn as_predicate(self) -> Predicate<'tcx> { pub fn as_predicate(self) -> Predicate<'tcx> {
Predicate(self.0) Predicate(self.0)
@ -251,6 +259,28 @@ impl<'tcx> ExistentialPredicate<'tcx> {
pub type PolyExistentialPredicate<'tcx> = ty::Binder<'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>> { impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
/// Returns the "principal `DefId`" of this set of existential predicates. /// 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> { impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Clause<'tcx> {
fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self { fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
let p: Predicate<'tcx> = from.upcast(tcx); 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> { impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyRegionOutlivesPredicate<'tcx>> for Predicate<'tcx> {
fn upcast_from(from: PolyRegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self { fn upcast_from(from: PolyRegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
from.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).upcast(tcx) 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 { fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self {
Ty::new_pat(interner, ty, pat) 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 /// Type utilities

View file

@ -565,42 +565,6 @@ impl<'tcx> TyCtxt<'tcx> {
Ok(()) 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 /// 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 /// (i.e. an async closure). These are all represented by `hir::Closure`, and all
/// have the same `DefKind`. /// have the same `DefKind`.

View file

@ -5,9 +5,25 @@ edition = "2021"
[dependencies] [dependencies]
# tidy-alphabetical-start # 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 = { path = "../rustc_type_ir", default-features = false }
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
tracing = "0.1"
# tidy-alphabetical-end # tidy-alphabetical-end
[features] [features]
default = ["nightly"] 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::fold::TypeFoldable;
use rustc_type_ir::relate::Relate; 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}; use rustc_type_ir::{self as ty, Interner};
pub trait SolverDelegate: Sized { pub trait SolverDelegate: Sized {
type Interner: Interner; type Interner: Interner;
fn interner(&self) -> Self::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_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
fn universe_of_lt(&self, lt: ty::RegionVid) -> 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>; fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
@ -74,4 +88,102 @@ pub trait SolverDelegate: Sized {
T: TypeFoldable<Self::Interner>; T: TypeFoldable<Self::Interner>;
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T; 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. //! 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. //! 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 canonicalizer;
pub mod infcx; pub mod infcx;
pub mod resolve; 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, //! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
//! relate them structurally. //! relate them structurally.
use super::infcx::SolverDelegate; use rustc_type_ir::inherent::*;
use super::EvalCtxt; use rustc_type_ir::{self as ty, Interner};
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty;
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)] #[instrument(level = "trace", skip(self), ret)]
pub(super) fn compute_alias_relate_goal( pub(super) fn compute_alias_relate_goal(
&mut self, &mut self,
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, goal: Goal<I, (I::Term, I::Term, ty::AliasRelationDirection)>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let tcx = self.interner(); let tcx = self.interner();
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); 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. //! 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; 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. /// A candidate is a possible way to prove a goal.
/// ///
/// It consists of both the `source`, which describes how that goal would be proven, /// It consists of both the `source`, which describes how that goal would be proven,
/// and the `result` when using the given `source`. /// and the `result` when using the given `source`.
#[derive(Derivative)] #[derive(derivative::Derivative)]
#[derivative(Debug(bound = ""), Clone(bound = ""))] #[derivative(Debug(bound = ""), Clone(bound = ""))]
pub(super) struct Candidate<I: Interner> { pub(super) struct Candidate<I: Interner> {
pub(super) source: CandidateSource<I>, 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. /// Methods used to assemble candidates for either trait or projection goals.
pub(super) trait GoalKind<'tcx>: pub(super) trait GoalKind<Infcx, I = <Infcx as SolverDelegate>::Interner>:
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display 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 /// Try equating an assumption predicate against a goal's predicate. If it
/// holds, then execute the `then` callback, which should do any additional /// holds, then execute the `then` callback, which should do any additional
/// work, then produce a response (typically by executing /// work, then produce a response (typically by executing
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]). /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
fn probe_and_match_goal_against_assumption( fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
source: CandidateSource<TyCtxt<'tcx>>, source: CandidateSource<I>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
assumption: ty::Clause<'tcx>, assumption: I::Clause,
then: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>) -> QueryResult<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// Consider a clause, which consists of a "assumption" and some "requirements", /// Consider a clause, which consists of a "assumption" and some "requirements",
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our /// to satisfy a goal. If the requirements hold, then attempt to satisfy our
/// goal by equating it with the assumption. /// goal by equating it with the assumption.
fn probe_and_consider_implied_clause( fn probe_and_consider_implied_clause(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
parent_source: CandidateSource<TyCtxt<'tcx>>, parent_source: CandidateSource<I>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
assumption: ty::Clause<'tcx>, assumption: I::Clause,
requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>, requirements: impl IntoIterator<Item = (GoalSource, Goal<I, I::Predicate>)>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| { Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| {
for (nested_source, goal) in requirements { for (nested_source, goal) in requirements {
ecx.add_goal(nested_source, goal); 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, /// additionally checking all of the supertraits and object bounds to hold,
/// since they're not implied by the well-formedness of the object type. /// since they're not implied by the well-formedness of the object type.
fn probe_and_consider_object_bound_candidate( fn probe_and_consider_object_bound_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
source: CandidateSource<TyCtxt<'tcx>>, source: CandidateSource<I>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
assumption: ty::Clause<'tcx>, assumption: I::Clause,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
let tcx = ecx.interner(); let tcx = ecx.interner();
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {
bug!("expected object type in `probe_and_consider_object_bound_candidate`"); panic!("expected object type in `probe_and_consider_object_bound_candidate`");
}; };
ecx.add_goals( ecx.add_goals(
GoalSource::ImplWhereBound, GoalSource::ImplWhereBound,
@ -104,10 +99,10 @@ pub(super) trait GoalKind<'tcx>:
} }
fn consider_impl_candidate( fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
impl_def_id: DefId, impl_def_id: I::DefId,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// If the predicate contained an error, we want to avoid emitting unnecessary trait /// 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 /// 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 /// Trait goals always hold while projection goals never do. This is a bit arbitrary
/// but prevents incorrect normalization while hiding any trait errors. /// but prevents incorrect normalization while hiding any trait errors.
fn consider_error_guaranteed_candidate( fn consider_error_guaranteed_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
guar: ErrorGuaranteed, guar: I::ErrorGuaranteed,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A type implements an `auto trait` if its components do as well. /// A type implements an `auto trait` if its components do as well.
/// ///
/// These components are given by built-in rules from /// These components are given by built-in rules from
/// [`structural_traits::instantiate_constituent_tys_for_auto_trait`]. /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`].
fn consider_auto_trait_candidate( fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A trait alias holds if the RHS traits and `where` clauses hold. /// A trait alias holds if the RHS traits and `where` clauses hold.
fn consider_trait_alias_candidate( fn consider_trait_alias_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A type is `Sized` if its tail component is `Sized`. /// A type is `Sized` if its tail component is `Sized`.
/// ///
/// These components are given by built-in rules from /// These components are given by built-in rules from
/// [`structural_traits::instantiate_constituent_tys_for_sized_trait`]. /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
fn consider_builtin_sized_candidate( fn consider_builtin_sized_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`. /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
/// ///
/// These components are given by built-in rules from /// These components are given by built-in rules from
/// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`]. /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`].
fn consider_builtin_copy_clone_candidate( fn consider_builtin_copy_clone_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A type is `PointerLike` if we can compute its layout, and that layout /// A type is `PointerLike` if we can compute its layout, and that layout
/// matches the layout of `usize`. /// matches the layout of `usize`.
fn consider_builtin_pointer_like_candidate( fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A type is a `FnPtr` if it is of `FnPtr` type. /// A type is a `FnPtr` if it is of `FnPtr` type.
fn consider_builtin_fn_ptr_trait_candidate( fn consider_builtin_fn_ptr_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>` /// 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. /// family of traits where `A` is given by the signature of the type.
fn consider_builtin_fn_trait_candidates( fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
kind: ty::ClosureKind, 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 /// An async closure is known to implement the `AsyncFn<A>` family of traits
/// where `A` is given by the signature of the type. /// where `A` is given by the signature of the type.
fn consider_builtin_async_fn_trait_candidates( fn consider_builtin_async_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
kind: ty::ClosureKind, kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which /// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
/// is used internally to delay computation for async closures until after /// is used internally to delay computation for async closures until after
/// upvar analysis is performed in HIR typeck. /// upvar analysis is performed in HIR typeck.
fn consider_builtin_async_fn_kind_helper_candidate( fn consider_builtin_async_fn_kind_helper_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// `Tuple` is implemented if the `Self` type is a tuple. /// `Tuple` is implemented if the `Self` type is a tuple.
fn consider_builtin_tuple_candidate( fn consider_builtin_tuple_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// `Pointee` is always implemented. /// `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 /// the built-in types. For structs, the metadata type is given by the struct
/// tail. /// tail.
fn consider_builtin_pointee_candidate( fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A coroutine (that comes from an `async` desugaring) is known to implement /// 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 /// `Future<Output = O>`, where `O` is given by the coroutine's return type
/// that was computed during type-checking. /// that was computed during type-checking.
fn consider_builtin_future_candidate( fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A coroutine (that comes from a `gen` desugaring) is known to implement /// 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 /// `Iterator<Item = O>`, where `O` is given by the generator's yield type
/// that was computed during type-checking. /// that was computed during type-checking.
fn consider_builtin_iterator_candidate( fn consider_builtin_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A coroutine (that comes from a `gen` desugaring) is known to implement /// A coroutine (that comes from a `gen` desugaring) is known to implement
/// `FusedIterator` /// `FusedIterator`
fn consider_builtin_fused_iterator_candidate( fn consider_builtin_fused_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_async_iterator_candidate( fn consider_builtin_async_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to /// 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, /// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
/// and return types of the coroutine computed during type-checking. /// and return types of the coroutine computed during type-checking.
fn consider_builtin_coroutine_candidate( fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_discriminant_kind_candidate( fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_async_destruct_candidate( fn consider_builtin_async_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_destruct_candidate( fn consider_builtin_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
fn consider_builtin_transmute_candidate( fn consider_builtin_transmute_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>; ) -> Result<Candidate<I>, NoSolution>;
/// Consider (possibly several) candidates to upcast or unsize a type to another /// Consider (possibly several) candidates to upcast or unsize a type to another
/// type, excluding the coercion of a sized type into a `dyn Trait`. /// 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 /// otherwise recompute this for codegen. This is a bit of a mess but the
/// easiest way to maintain the existing behavior for now. /// easiest way to maintain the existing behavior for now.
fn consider_structural_builtin_unsize_candidates( fn consider_structural_builtin_unsize_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Vec<Candidate<TyCtxt<'tcx>>>; ) -> Vec<Candidate<I>>;
} }
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> { impl<Infcx, I> EvalCtxt<'_, Infcx>
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>( where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<Infcx>>(
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
) -> Vec<Candidate<TyCtxt<'tcx>>> { ) -> Vec<Candidate<I>> {
let Ok(normalized_self_ty) = let Ok(normalized_self_ty) =
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty()) self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
else { else {
@ -291,7 +290,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); 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(), self.interner(),
goal.predicate.with_self_ty(self.interner(), normalized_self_ty), goal.predicate.with_self_ty(self.interner(), normalized_self_ty),
); );
@ -301,7 +300,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
let mut candidates = vec![]; 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); 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_object_bound_candidates(goal, &mut candidates);
self.assemble_blanket_impl_candidates(goal, &mut candidates);
self.assemble_param_env_candidates(goal, &mut candidates); self.assemble_param_env_candidates(goal, &mut candidates);
match self.solver_mode() { match self.solver_mode() {
@ -326,7 +323,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
pub(super) fn forced_ambiguity( pub(super) fn forced_ambiguity(
&mut self, &mut self,
cause: MaybeCause, cause: MaybeCause,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
// This may fail if `try_evaluate_added_goals` overflows because it // This may fail if `try_evaluate_added_goals` overflows because it
// fails to reach a fixpoint but ends up getting an error after // fails to reach a fixpoint but ends up getting an error after
// running for some additional step. // running for some additional step.
@ -339,149 +336,36 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
} }
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>( fn assemble_impl_candidates<G: GoalKind<Infcx>>(
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, candidates: &mut Vec<Candidate<I>>,
) { ) {
let tcx = self.interner(); let tcx = self.interner();
let self_ty = goal.predicate.self_ty(); tcx.for_each_relevant_impl(
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); goal.predicate.trait_def_id(tcx),
let mut consider_impls_for_simplified_type = |simp| { goal.predicate.self_ty(),
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) { |impl_def_id| {
for &impl_def_id in impls_for_type { // For every `default impl`, there's always a non-default `impl`
// For every `default impl`, there's always a non-default `impl` // that will *also* apply. There's no reason to register a candidate
// 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.
// for this impl, since it is *not* proof that the trait goal holds. if tcx.impl_is_default(impl_def_id) {
if tcx.defaultness(impl_def_id).is_default() { return;
return;
}
match G::consider_impl_candidate(self, goal, impl_def_id) {
Ok(candidate) => candidates.push(candidate),
Err(NoSolution) => (),
}
} }
}
};
match self_ty.kind() { match G::consider_impl_candidate(self, goal, impl_def_id) {
ty::Bool Ok(candidate) => candidates.push(candidate),
| ty::Char Err(NoSolution) => (),
| 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)] #[instrument(level = "trace", skip_all)]
fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>( fn assemble_builtin_impl_candidates<G: GoalKind<Infcx>>(
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, candidates: &mut Vec<Candidate<I>>,
) {
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>>>,
) { ) {
let tcx = self.interner(); let tcx = self.interner();
let trait_def_id = goal.predicate.trait_def_id(tcx); 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) G::consider_auto_trait_candidate(self, goal)
} else if tcx.trait_is_alias(trait_def_id) { } else if tcx.trait_is_alias(trait_def_id) {
G::consider_trait_alias_candidate(self, goal) 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) G::consider_builtin_sized_candidate(self, goal)
} else if tcx.is_lang_item(trait_def_id, LangItem::Copy) } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy)
|| tcx.is_lang_item(trait_def_id, LangItem::Clone) || tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone)
{ {
G::consider_builtin_copy_clone_candidate(self, goal) 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) 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) 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) { } 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) 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) { } 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) G::consider_builtin_transmute_candidate(self, goal)
} else { } else {
Err(NoSolution) Err(NoSolution)
@ -545,18 +429,18 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// There may be multiple unsize candidates for a trait with several supertraits: // There may be multiple unsize candidates for a trait with several supertraits:
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>` // `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)); candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
} }
} }
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
fn assemble_param_env_candidates<G: GoalKind<'tcx>>( fn assemble_param_env_candidates<G: GoalKind<Infcx>>(
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, 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( candidates.extend(G::probe_and_consider_implied_clause(
self, self,
CandidateSource::ParamEnv(i), CandidateSource::ParamEnv(i),
@ -568,10 +452,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
} }
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>( fn assemble_alias_bound_candidates<G: GoalKind<Infcx>>(
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, candidates: &mut Vec<Candidate<I>>,
) { ) {
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| { let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates); 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. /// If so, continue searching by recursively calling after normalization.
// FIXME: This may recurse infinitely, but I can't seem to trigger it without // 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. // 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, &mut self,
self_ty: Ty<'tcx>, self_ty: I::Ty,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, candidates: &mut Vec<Candidate<I>>,
) { ) {
let (kind, alias_ty) = match *self_ty.kind() { let (kind, alias_ty) = match self_ty.kind() {
ty::Bool ty::Bool
| ty::Char | ty::Char
| ty::Int(_) | ty::Int(_)
@ -621,7 +505,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Error(_) => return, | ty::Error(_) => return,
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => { 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(_)) => { 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(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
ty::Alias(ty::Inherent | ty::Weak, _) => { ty::Alias(ty::Inherent | ty::Weak, _) => {
self.interner().sess.dcx().span_delayed_bug( self.interner().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
DUMMY_SP,
format!("could not normalize {self_ty}, it is not WF"),
);
return; return;
} }
}; };
for assumption in for assumption in self
self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args) .interner()
.item_bounds(alias_ty.def_id)
.iter_instantiated(self.interner(), &alias_ty.args)
{ {
candidates.extend(G::probe_and_consider_implied_clause( candidates.extend(G::probe_and_consider_implied_clause(
self, self,
@ -672,18 +555,18 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
} }
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
fn assemble_object_bound_candidates<G: GoalKind<'tcx>>( fn assemble_object_bound_candidates<G: GoalKind<Infcx>>(
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, candidates: &mut Vec<Candidate<I>>,
) { ) {
let tcx = self.interner(); 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; return;
} }
let self_ty = goal.predicate.self_ty(); let self_ty = goal.predicate.self_ty();
let bounds = match *self_ty.kind() { let bounds = match self_ty.kind() {
ty::Bool ty::Bool
| ty::Char | ty::Char
| ty::Int(_) | ty::Int(_)
@ -711,12 +594,12 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Error(_) => return, | ty::Error(_) => return,
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) 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, ty::Dynamic(bounds, ..) => bounds,
}; };
// Do not consider built-in object impls for non-object-safe types. // 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; return;
} }
@ -745,7 +628,9 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// a projection goal. // a projection goal.
if let Some(principal) = bounds.principal() { if let Some(principal) = bounds.principal() {
let principal_trait_ref = principal.with_self_ty(tcx, self_ty); 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( candidates.extend(G::probe_and_consider_object_bound_candidate(
self, self,
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)), 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 /// To do so we add an ambiguous candidate in case such an unknown impl could
/// apply to the current goal. /// apply to the current goal.
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>( fn assemble_coherence_unknowable_candidates<G: GoalKind<Infcx>>(
&mut self, &mut self,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, candidates: &mut Vec<Candidate<I>>,
) { ) {
let tcx = self.interner(); 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 // to improve this however. However, this should make it fairly straightforward to refine
// the filtering going forward, so it seems alright-ish for now. // the filtering going forward, so it seems alright-ish for now.
#[instrument(level = "debug", skip(self, goal))] #[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, &mut self,
goal: Goal<'tcx, G>, goal: Goal<I, G>,
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>, candidates: &mut Vec<Candidate<I>>,
) { ) {
let tcx = self.interner(); 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)); goal.with(tcx, goal.predicate.trait_ref(tcx));
let mut trait_candidates_from_env = vec![]; let mut trait_candidates_from_env = vec![];
@ -823,7 +708,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
false false
} }
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true, 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 // 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 /// to somehow try to merge the candidates into one. If that fails, we return
/// ambiguity. /// ambiguity.
#[instrument(level = "debug", skip(self), ret)] #[instrument(level = "debug", skip(self), ret)]
pub(super) fn merge_candidates( pub(super) fn merge_candidates(&mut self, candidates: Vec<Candidate<I>>) -> QueryResult<I> {
&mut self,
candidates: Vec<Candidate<TyCtxt<'tcx>>>,
) -> QueryResult<'tcx> {
// First try merging all candidates. This is complete and fully sound. // First try merging all candidates. This is complete and fully sound.
let responses = candidates.iter().map(|c| c.result).collect::<Vec<_>>(); let responses = candidates.iter().map(|c| c.result).collect::<Vec<_>>();
if let Some(result) = self.try_merge_responses(&responses) { if let Some(result) = self.try_merge_responses(&responses) {

View file

@ -3,20 +3,16 @@
use rustc_ast_ir::{Movability, Mutability}; use rustc_ast_ir::{Movability, Mutability};
use rustc_data_structures::fx::FxHashMap; 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::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_type_ir::inherent::*; use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem; 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 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. // 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)] #[instrument(level = "trace", skip(ecx), ret)]
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<Infcx, I>( pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<Infcx, I>(
ecx: &EvalCtxt<'_, Infcx>, 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"), .expect("expected to be able to unify goal projection with dyn's projection"),
); );
proj.term.expect_type() proj.term.expect_ty()
} else { } else {
ty.super_fold_with(self) ty.super_fold_with(self)
} }

View file

@ -8,60 +8,52 @@
//! section of the [rustc-dev-guide][c]. //! section of the [rustc-dev-guide][c].
//! //!
//! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html //! [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::iter;
use std::ops::Deref;
trait ResponseT<'tcx> { use rustc_index::IndexVec;
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>>; 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>> { impl<I: Interner> ResponseT<I> for Response<I> {
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> { fn var_values(&self) -> CanonicalVarValues<I> {
self.var_values self.var_values
} }
} }
impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> { impl<I: Interner, T> ResponseT<I> for inspect::State<I, T> {
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> { fn var_values(&self) -> CanonicalVarValues<I> {
self.var_values 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 /// Canonicalizes the goal remembering the original values
/// for each bound variable. /// for each bound variable.
pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>( pub(super) fn canonicalize_goal<T: TypeFoldable<I>>(
&self, &self,
goal: Goal<'tcx, T>, goal: Goal<I, T>,
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) { ) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) {
let opaque_types = self.infcx.clone_opaque_types_for_query_response(); let opaque_types = self.infcx.clone_opaque_types_for_query_response();
let (goal, opaque_types) = let (goal, opaque_types) =
(goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx)); (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( pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
&mut self, &mut self,
certainty: Certainty, certainty: Certainty,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
self.inspect.make_canonical_response(certainty); self.inspect.make_canonical_response(certainty);
let goals_certainty = self.try_evaluate_added_goals()?; 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 // We only check for leaks from universes which were entered inside
// of the query. // of the query.
self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { self.infcx.leak_check(self.max_input_universe).map_err(|NoSolution| {
trace!(?e, "failed the leak check"); trace!("failed the leak check");
NoSolution NoSolution
})?; })?;
@ -121,7 +113,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
assert!(normalizes_to_goals.is_empty()); assert!(normalizes_to_goals.is_empty());
if goals.is_empty() { if goals.is_empty() {
assert_matches!(goals_certainty, Certainty::Yes); assert!(matches!(goals_certainty, Certainty::Yes));
} }
} }
(certainty, NestedNormalizationGoals(goals)) (certainty, NestedNormalizationGoals(goals))
@ -160,7 +152,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
pub(in crate::solve) fn make_ambiguous_response_no_constraints( pub(in crate::solve) fn make_ambiguous_response_no_constraints(
&self, &self,
maybe_cause: MaybeCause, maybe_cause: MaybeCause,
) -> CanonicalResponse<'tcx> { ) -> CanonicalResponse<I> {
response_no_constraints_raw( response_no_constraints_raw(
self.interner(), self.interner(),
self.max_input_universe, self.max_input_universe,
@ -180,8 +172,8 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
fn compute_external_query_constraints( fn compute_external_query_constraints(
&self, &self,
certainty: Certainty, certainty: Certainty,
normalization_nested_goals: NestedNormalizationGoals<TyCtxt<'tcx>>, normalization_nested_goals: NestedNormalizationGoals<I>,
) -> ExternalConstraintsData<TyCtxt<'tcx>> { ) -> ExternalConstraintsData<I> {
// We only return region constraints once the certainty is `Yes`. This // We only return region constraints once the certainty is `Yes`. This
// is necessary as we may drop nested goals on ambiguity, which may result // is necessary as we may drop nested goals on ambiguity, which may result
// in unconstrained inference variables in the region constraints. It also // 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-5-ambig.rs` and
// `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`. // `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`.
let region_constraints = if certainty == Certainty::Yes { let region_constraints = if certainty == Certainty::Yes {
// Cannot use `take_registered_region_obligations` as we may compute the response self.infcx.make_deduplicated_outlives_constraints()
// 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()
} else { } else {
Default::default() Default::default()
}; };
@ -240,10 +213,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// the `normalization_nested_goals` /// the `normalization_nested_goals`
pub(super) fn instantiate_and_apply_query_response( pub(super) fn instantiate_and_apply_query_response(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
original_values: Vec<ty::GenericArg<'tcx>>, original_values: Vec<I::GenericArg>,
response: CanonicalResponse<'tcx>, response: CanonicalResponse<I>,
) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty) { ) -> (NestedNormalizationGoals<I>, Certainty) {
let instantiation = Self::compute_query_response_instantiation_values( let instantiation = Self::compute_query_response_instantiation_values(
self.infcx, self.infcx,
&original_values, &original_values,
@ -251,7 +224,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
); );
let Response { var_values, external_constraints, certainty } = 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); Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values);
@ -259,7 +232,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
region_constraints, region_constraints,
opaque_types, opaque_types,
normalization_nested_goals, normalization_nested_goals,
} = external_constraints.deref(); } = &*external_constraints;
self.register_region_constraints(region_constraints); self.register_region_constraints(region_constraints);
self.register_new_opaque_types(opaque_types); self.register_new_opaque_types(opaque_types);
(normalization_nested_goals.clone(), certainty) (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 /// This returns the canoncial variable values to instantiate the bound variables of
/// the canonical response. This depends on the `original_values` for the /// the canonical response. This depends on the `original_values` for the
/// bound variables. /// bound variables.
fn compute_query_response_instantiation_values<T: ResponseT<'tcx>>( fn compute_query_response_instantiation_values<T: ResponseT<I>>(
infcx: &InferCtxt<'tcx>, infcx: &Infcx,
original_values: &[ty::GenericArg<'tcx>], original_values: &[I::GenericArg],
response: &Canonical<'tcx, T>, response: &Canonical<I, T>,
) -> CanonicalVarValues<TyCtxt<'tcx>> { ) -> CanonicalVarValues<I> {
// FIXME: Longterm canonical queries should deal with all placeholders // FIXME: Longterm canonical queries should deal with all placeholders
// created inside of the query directly instead of returning them to the // created inside of the query directly instead of returning them to the
// caller. // caller.
@ -294,35 +267,35 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// inference variable of the input right away, which is more performant. // inference variable of the input right away, which is more performant.
let mut opt_values = IndexVec::from_elem_n(None, response.variables.len()); 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) { for (original_value, result_value) in iter::zip(original_values, var_values.var_values) {
match result_value.unpack() { match result_value.kind() {
GenericArgKind::Type(t) => { ty::GenericArgKind::Type(t) => {
if let &ty::Bound(debruijn, b) = t.kind() { if let ty::Bound(debruijn, b) = t.kind() {
assert_eq!(debruijn, ty::INNERMOST); assert_eq!(debruijn, ty::INNERMOST);
opt_values[b.var] = Some(*original_value); opt_values[b.var()] = Some(*original_value);
} }
} }
GenericArgKind::Lifetime(r) => { ty::GenericArgKind::Lifetime(r) => {
if let ty::ReBound(debruijn, br) = *r { if let ty::ReBound(debruijn, br) = r.kind() {
assert_eq!(debruijn, ty::INNERMOST); assert_eq!(debruijn, ty::INNERMOST);
opt_values[br.var] = Some(*original_value); opt_values[br.var()] = Some(*original_value);
} }
} }
GenericArgKind::Const(c) => { ty::GenericArgKind::Const(c) => {
if let ty::ConstKind::Bound(debruijn, b) = c.kind() { if let ty::ConstKind::Bound(debruijn, bv) = c.kind() {
assert_eq!(debruijn, ty::INNERMOST); 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( let var_values = infcx.interner().mk_args_from_iter(
|(index, info)| { response.variables.into_iter().enumerate().map(|(index, info)| {
if info.universe() != ty::UniverseIndex::ROOT { if info.universe() != ty::UniverseIndex::ROOT {
// A variable from inside a binder of the query. While ideally these shouldn't // 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 // exist at all (see the FIXME at the start of this method), we have to deal with
// them for now. // 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()) ty::UniverseIndex::from(prev_universe.index() + idx.index())
}) })
} else if info.is_existential() { } 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 // 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 // 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. // 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 v
} else { } else {
infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe) infcx.instantiate_canonical_var_with_infer(info, |_| prev_universe)
} }
} else { } else {
// For placeholders which were already part of the input, we simply map this // For placeholders which were already part of the input, we simply map this
// universal bound variable back the placeholder of the input. // universal bound variable back the placeholder of the input.
original_values[info.expect_placeholder_index()] original_values[info.expect_placeholder_index()]
} }
}, }),
)); );
CanonicalVarValues { var_values } CanonicalVarValues { var_values }
} }
@ -363,40 +336,35 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// always relate them structurally here. /// always relate them structurally here.
#[instrument(level = "trace", skip(infcx))] #[instrument(level = "trace", skip(infcx))]
fn unify_query_var_values( fn unify_query_var_values(
infcx: &InferCtxt<'tcx>, infcx: &Infcx,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
original_values: &[ty::GenericArg<'tcx>], original_values: &[I::GenericArg],
var_values: CanonicalVarValues<TyCtxt<'tcx>>, var_values: CanonicalVarValues<I>,
) { ) {
assert_eq!(original_values.len(), var_values.len()); assert_eq!(original_values.len(), var_values.len());
let cause = ObligationCause::dummy();
for (&orig, response) in iter::zip(original_values, var_values.var_values) { for (&orig, response) in iter::zip(original_values, var_values.var_values) {
let InferOk { value: (), obligations } = infcx let goals = infcx.eq_structurally_relating_aliases(param_env, orig, response).unwrap();
.at(&cause, param_env) assert!(goals.is_empty());
.eq_structurally_relating_aliases(orig, response)
.unwrap();
assert!(obligations.is_empty());
} }
} }
fn register_region_constraints( fn register_region_constraints(
&mut self, &mut self,
outlives: &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>], outlives: &[ty::OutlivesPredicate<I, I::GenericArg>],
) { ) {
for &ty::OutlivesPredicate(lhs, rhs) in outlives { for &ty::OutlivesPredicate(lhs, rhs) in outlives {
match lhs.unpack() { match lhs.kind() {
GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), ty::GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), ty::GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
GenericArgKind::Const(_) => bug!("const 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 { for &(key, ty) in opaque_types {
let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; self.infcx.inject_new_hidden_type_unchecked(key, ty);
self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty);
} }
} }
} }
@ -412,7 +380,7 @@ pub(in crate::solve) fn make_canonical_state<Infcx, T, I>(
data: T, data: T,
) -> inspect::CanonicalState<I, T> ) -> inspect::CanonicalState<I, T>
where where
Infcx: IrSolverDelegate<Interner = I>, Infcx: SolverDelegate<Interner = I>,
I: Interner, I: Interner,
T: TypeFoldable<I>, T: TypeFoldable<I>,
{ {
@ -426,47 +394,3 @@ where
state, 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 std::ops::ControlFlow;
use crate::solve::infcx::SolverDelegate; use rustc_data_structures::stack::ensure_sufficient_stack;
use crate::traits::coherence; 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 crate::infcx::SolverDelegate;
use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; use crate::solve::inspect::{self, ProofTreeBuilder};
use super::{search_graph::SearchGraph, Goal}; use crate::solve::search_graph::SearchGraph;
use super::{GoalSource, SolverMode}; use crate::solve::{
search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind,
GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData,
QueryResult, SolverMode, FIXPOINT_STEP_LIMIT,
};
pub(super) mod canonical; pub(super) mod canonical;
mod probe; mod probe;
pub struct EvalCtxt<'a, Infcx, I = <Infcx as IrSolverDelegate>::Interner> pub struct EvalCtxt<'a, Infcx, I = <Infcx as SolverDelegate>::Interner>
where where
Infcx: IrSolverDelegate<Interner = I>, Infcx: SolverDelegate<Interner = I>,
I: Interner, I: Interner,
{ {
/// The inference context that backs (mostly) inference and placeholder terms /// 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 /// Forgetting to replace the RHS with a fresh inference variable when we evaluate
/// this goal results in an ICE.. /// 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. /// 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> { 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 { pub enum GenerateProofTree {
Yes, Yes,
No, No,
} }
#[extension(pub trait InferCtxtEvalExt<'tcx>)] pub trait SolverDelegateEvalExt: SolverDelegate {
impl<'tcx> InferCtxt<'tcx> { 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. /// Evaluates a goal from **outside** of the trait solver.
/// ///
/// Using this while inside of the solver is wrong as it uses a new /// 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))] #[instrument(level = "debug", skip(self))]
fn evaluate_root_goal( fn evaluate_root_goal(
&self, &self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, goal: Goal<I, I::Predicate>,
generate_proof_tree: GenerateProofTree, 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| { EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal) 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 { pub(super) fn solver_mode(&self) -> SolverMode {
self.search_graph.solver_mode() 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 /// Creates a root evaluation context and search graph. This should only be
/// used from outside of any evaluation, and other methods should be preferred /// 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>( pub(super) fn enter_root<R>(
infcx: &InferCtxt<'tcx>, infcx: &Infcx,
generate_proof_tree: GenerateProofTree, generate_proof_tree: GenerateProofTree,
f: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>) -> R, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> R,
) -> (R, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) { ) -> (R, Option<inspect::GoalEvaluation<I>>) {
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal }; let mut search_graph = search_graph::SearchGraph::new(infcx.solver_mode());
let mut search_graph = search_graph::SearchGraph::new(mode);
let mut ecx = EvalCtxt { let mut ecx = EvalCtxt {
infcx: <&SolverDelegate<'tcx>>::from(infcx), infcx,
search_graph: &mut search_graph, search_graph: &mut search_graph,
nested_goals: NestedGoals::new(), nested_goals: NestedGoals::new(),
inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree), 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, // Only relevant when canonicalizing the response,
// which we don't do within this evaluation context. // which we don't do within this evaluation context.
predefined_opaques_in_body: infcx predefined_opaques_in_body: infcx
.tcx .interner()
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()), .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
max_input_universe: ty::UniverseIndex::ROOT, max_input_universe: ty::UniverseIndex::ROOT,
variables: ty::List::empty(), variables: Default::default(),
var_values: CanonicalVarValues::dummy(), var_values: CanonicalVarValues::dummy(),
is_normalizes_to_goal: false, is_normalizes_to_goal: false,
tainted: Ok(()), 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, /// This function takes care of setting up the inference context, setting the anchor,
/// and registering opaques from the canonicalized input. /// and registering opaques from the canonicalized input.
fn enter_canonical<R>( fn enter_canonical<R>(
tcx: TyCtxt<'tcx>, tcx: I,
search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>, search_graph: &'a mut search_graph::SearchGraph<I>,
canonical_input: CanonicalInput<'tcx>, canonical_input: CanonicalInput<I>,
canonical_goal_evaluation: &mut ProofTreeBuilder<SolverDelegate<'tcx>>, canonical_goal_evaluation: &mut ProofTreeBuilder<Infcx>,
f: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>, Goal<I, I::Predicate>) -> R,
) -> R { ) -> R {
let intercrate = match search_graph.solver_mode() { let (ref infcx, input, var_values) =
SolverMode::Normal => false, SolverDelegate::build_with_canonical(tcx, search_graph.solver_mode(), &canonical_input);
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 mut ecx = EvalCtxt { let mut ecx = EvalCtxt {
infcx: <&SolverDelegate<'tcx>>::from(infcx), infcx,
variables: canonical_input.variables, variables: canonical_input.variables,
var_values, var_values,
is_normalizes_to_goal: false, 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 { 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, ty);
ecx.infcx.inject_new_hidden_type_unchecked(key, hidden_ty);
} }
if !ecx.nested_goals.is_empty() { 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 // instead of taking them. This would cause an ICE here, since we have
// assertions against dropping an `InferCtxt` without taking opaques. // assertions against dropping an `InferCtxt` without taking opaques.
// FIXME: Once we remove support for the old impl we can remove this. // 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 result
} }
@ -268,15 +262,15 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
/// logic of the solver. /// logic of the solver.
/// ///
/// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] /// 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. /// outside of it.
#[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)] #[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)]
fn evaluate_canonical_goal( fn evaluate_canonical_goal(
tcx: TyCtxt<'tcx>, tcx: I,
search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>, search_graph: &'a mut search_graph::SearchGraph<I>,
canonical_input: CanonicalInput<'tcx>, canonical_input: CanonicalInput<I>,
goal_evaluation: &mut ProofTreeBuilder<SolverDelegate<'tcx>>, goal_evaluation: &mut ProofTreeBuilder<Infcx>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let mut canonical_goal_evaluation = let mut canonical_goal_evaluation =
goal_evaluation.new_canonical_goal_evaluation(canonical_input); goal_evaluation.new_canonical_goal_evaluation(canonical_input);
@ -315,7 +309,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
&mut self, &mut self,
goal_evaluation_kind: GoalEvaluationKind, goal_evaluation_kind: GoalEvaluationKind,
source: GoalSource, source: GoalSource,
goal: Goal<'tcx, ty::Predicate<'tcx>>, goal: Goal<I, I::Predicate>,
) -> Result<(bool, Certainty), NoSolution> { ) -> Result<(bool, Certainty), NoSolution> {
let (normalization_nested_goals, has_changed, certainty) = let (normalization_nested_goals, has_changed, certainty) =
self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?; self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?;
@ -336,8 +330,8 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
&mut self, &mut self,
goal_evaluation_kind: GoalEvaluationKind, goal_evaluation_kind: GoalEvaluationKind,
_source: GoalSource, _source: GoalSource,
goal: Goal<'tcx, ty::Predicate<'tcx>>, goal: Goal<I, I::Predicate>,
) -> Result<(NestedNormalizationGoals<TyCtxt<'tcx>>, bool, Certainty), NoSolution> { ) -> Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution> {
let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
let mut goal_evaluation = let mut goal_evaluation =
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); 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( fn instantiate_response_discarding_overflow(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
original_values: Vec<ty::GenericArg<'tcx>>, original_values: Vec<I::GenericArg>,
response: CanonicalResponse<'tcx>, response: CanonicalResponse<I>,
) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty, bool) { ) -> (NestedNormalizationGoals<I>, Certainty, bool) {
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty { if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty {
return (NestedNormalizationGoals::empty(), response.value.certainty, false); return (NestedNormalizationGoals::empty(), response.value.certainty, false);
} }
@ -393,7 +387,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
(normalization_nested_goals, certainty, has_changed) (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 Goal { param_env, predicate } = goal;
let kind = predicate.kind(); let kind = predicate.kind();
if let Some(kind) = kind.no_bound_vars() { 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 }) self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
} }
ty::PredicateKind::ConstEquate(_, _) => { 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) => { ty::PredicateKind::NormalizesTo(predicate) => {
self.compute_normalizes_to_goal(Goal { param_env, 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`. /// 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) 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 { pub(super) fn interner(&self) -> I {
self.infcx.interner() self.infcx.interner()
} }
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
pub(super) fn add_normalizes_to_goal( pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
&mut self,
mut goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
) {
goal.predicate = goal goal.predicate = goal
.predicate .predicate
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); .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))] #[instrument(level = "debug", skip(self))]
pub(super) fn add_goal( pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
&mut self,
source: GoalSource,
mut goal: ir::solve::Goal<I, I::Predicate>,
) {
goal.predicate = goal goal.predicate = goal
.predicate .predicate
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); .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( pub(super) fn add_goals(
&mut self, &mut self,
source: GoalSource, source: GoalSource,
goals: impl IntoIterator<Item = ir::solve::Goal<I, I::Predicate>>, goals: impl IntoIterator<Item = Goal<I, I::Predicate>>,
) { ) {
for goal in goals { for goal in goals {
self.add_goal(source, goal); 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. /// 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 { pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term {
match kind.kind() { match kind.kind() {
ir::TermKind::Ty(_) => self.next_ty_infer().into(), ty::TermKind::Ty(_) => self.next_ty_infer().into(),
ir::TermKind::Const(_) => self.next_const_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 /// 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. /// and is able to name all other placeholder and inference variables.
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
pub(super) fn term_is_fully_unconstrained( pub(super) fn term_is_fully_unconstrained(&self, goal: Goal<I, ty::NormalizesTo<I>>) -> bool {
&self,
goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
) -> bool {
let universe_of_term = match goal.predicate.term.kind() { let universe_of_term = match goal.predicate.term.kind() {
ir::TermKind::Ty(ty) => { ty::TermKind::Ty(ty) => {
if let ir::Infer(ir::TyVar(vid)) = ty.kind() { if let ty::Infer(ty::TyVar(vid)) = ty.kind() {
self.infcx.universe_of_ty(vid).unwrap() self.infcx.universe_of_ty(vid).unwrap()
} else { } else {
return false; return false;
} }
} }
ir::TermKind::Const(ct) => { ty::TermKind::Const(ct) => {
if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() { if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
self.infcx.universe_of_ct(vid).unwrap() self.infcx.universe_of_ct(vid).unwrap()
} else { } else {
return false; 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, term: I::Term,
universe_of_term: ir::UniverseIndex, universe_of_term: ty::UniverseIndex,
infcx: &'a Infcx, infcx: &'a Infcx,
} }
impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> {
fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> { fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
if self.universe_of_term.can_name(universe) { if self.universe_of_term.can_name(universe) {
ControlFlow::Continue(()) ControlFlow::Continue(())
} else { } 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> for ContainsTermOrNotNameable<'_, Infcx, I>
{ {
type Result = ControlFlow<()>; type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: I::Ty) -> Self::Result { fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
match t.kind() { match t.kind() {
ir::Infer(ir::TyVar(vid)) => { ty::Infer(ty::TyVar(vid)) => {
if let ir::TermKind::Ty(term) = self.term.kind() if let ty::TermKind::Ty(term) = self.term.kind()
&& let ir::Infer(ir::TyVar(term_vid)) = term.kind() && let ty::Infer(ty::TyVar(term_vid)) = term.kind()
&& self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid) && self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid)
{ {
ControlFlow::Break(()) 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()) 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() { if t.has_non_region_infer() || t.has_placeholders() {
t.super_visit_with(self) 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 { fn visit_const(&mut self, c: I::Const) -> Self::Result {
match c.kind() { match c.kind() {
ir::ConstKind::Infer(ir::InferConst::Var(vid)) => { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
if let ir::TermKind::Const(term) = self.term.kind() if let ty::TermKind::Const(term) = self.term.kind()
&& let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = 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) && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid)
{ {
ControlFlow::Break(()) 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()) 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() { if c.has_non_region_infer() || c.has_placeholders() {
c.super_visit_with(self) c.super_visit_with(self)
@ -741,7 +723,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
lhs: T, lhs: T,
rhs: T, rhs: T,
) -> Result<(), NoSolution> { ) -> 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. /// 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( pub(super) fn relate_rigid_alias_non_alias(
&mut self, &mut self,
param_env: I::ParamEnv, param_env: I::ParamEnv,
alias: ir::AliasTerm<I>, alias: ty::AliasTerm<I>,
variance: ir::Variance, variance: ty::Variance,
term: I::Term, term: I::Term,
) -> Result<(), NoSolution> { ) -> Result<(), NoSolution> {
// NOTE: this check is purely an optimization, the structural eq would // 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 // Alternatively we could modify `Equate` for this case by adding another
// variant to `StructurallyRelateAliases`. // variant to `StructurallyRelateAliases`.
let identity_args = self.fresh_args_for_item(alias.def_id); 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 ctor_term = rigid_ctor.to_term(tcx);
let obligations = let obligations =
self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?; 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, sub: T,
sup: T, sup: T,
) -> Result<(), NoSolution> { ) -> 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)] #[instrument(level = "trace", skip(self, param_env), ret)]
@ -811,7 +793,7 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
&mut self, &mut self,
param_env: I::ParamEnv, param_env: I::ParamEnv,
lhs: T, lhs: T,
variance: ir::Variance, variance: ty::Variance,
rhs: T, rhs: T,
) -> Result<(), NoSolution> { ) -> Result<(), NoSolution> {
let goals = self.infcx.relate(param_env, lhs, variance, rhs)?; 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, param_env: I::ParamEnv,
lhs: T, lhs: T,
rhs: T, rhs: T,
) -> Result<Vec<ir::solve::Goal<I, I::Predicate>>, NoSolution> { ) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs) self.infcx.relate(param_env, lhs, ty::Variance::Invariant, rhs)
} }
pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>( pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
&self, &self,
value: ir::Binder<I, T>, value: ty::Binder<I, T>,
) -> T { ) -> T {
self.infcx.instantiate_binder_with_infer(value) self.infcx.instantiate_binder_with_infer(value)
} }
pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>( pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
&self, &self,
value: ir::Binder<I, T>, value: ty::Binder<I, T>,
f: impl FnOnce(T) -> U, f: impl FnOnce(T) -> U,
) -> U { ) -> U {
self.infcx.enter_forall(value, f) self.infcx.enter_forall(value, f)
@ -863,36 +845,29 @@ impl<Infcx: IrSolverDelegate<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
} }
args args
} }
}
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> { pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) { self.infcx.register_ty_outlives(ty, lt);
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` // `b : a` ==> `a <= b`
// (inlined from `InferCtxt::region_outlives_predicate`) self.infcx.sub_regions(b, a);
self.infcx.sub_regions(
rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP),
b,
a,
);
} }
/// Computes the list of goals required for `arg` to be well-formed /// Computes the list of goals required for `arg` to be well-formed
pub(super) fn well_formed_goals( pub(super) fn well_formed_goals(
&self, &self,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
arg: ty::GenericArg<'tcx>, arg: I::GenericArg,
) -> Option<impl Iterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>> { ) -> Option<Vec<Goal<I, I::Predicate>>> {
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg) self.infcx.well_formed_goals(param_env, arg)
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
} }
/*
pub(super) fn is_transmutable( pub(super) fn is_transmutable(
&self, &self,
src_and_dst: rustc_transmute::Types<'tcx>, src_and_dst: rustc_transmute::Types<I>,
assume: rustc_transmute::Assume, assume: rustc_transmute::Assume,
) -> Result<Certainty, NoSolution> { ) -> Result<Certainty, NoSolution> {
use rustc_transmute::Answer; use rustc_transmute::Answer;
@ -906,46 +881,55 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
Answer::No(_) | Answer::If(_) => Err(NoSolution), Answer::No(_) | Answer::If(_) => Err(NoSolution),
} }
} }
*/
pub(super) fn trait_ref_is_knowable( pub(super) fn trait_ref_is_knowable(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
trait_ref: ty::TraitRef<'tcx>, trait_ref: ty::TraitRef<I>,
) -> Result<bool, NoSolution> { ) -> Result<bool, NoSolution> {
let infcx = self.infcx; let infcx = self.infcx;
let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty); let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
coherence::trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) infcx.trait_ref_is_knowable(trait_ref, lazily_normalize_ty)
.map(|is_knowable| is_knowable.is_ok())
} }
pub(super) fn can_define_opaque_ty(&self, def_id: impl Into<DefId>) -> bool { pub(super) fn fetch_eligible_assoc_item(
self.infcx.can_define_opaque_ty(def_id) &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( pub(super) fn insert_hidden_type(
&mut self, &mut self,
opaque_type_key: OpaqueTypeKey<'tcx>, opaque_type_key: ty::OpaqueTypeKey<I>,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
hidden_ty: Ty<'tcx>, hidden_ty: I::Ty,
) -> Result<(), NoSolution> { ) -> Result<(), NoSolution> {
let mut goals = Vec::new(); let mut goals = Vec::new();
self.infcx.insert_hidden_type( self.infcx.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?;
opaque_type_key,
DUMMY_SP,
param_env,
hidden_ty,
&mut goals,
)?;
self.add_goals(GoalSource::Misc, goals); self.add_goals(GoalSource::Misc, goals);
Ok(()) Ok(())
} }
pub(super) fn add_item_bounds_for_hidden_type( pub(super) fn add_item_bounds_for_hidden_type(
&mut self, &mut self,
opaque_def_id: DefId, opaque_def_id: I::DefId,
opaque_args: ty::GenericArgsRef<'tcx>, opaque_args: I::GenericArgs,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
hidden_ty: Ty<'tcx>, hidden_ty: I::Ty,
) { ) {
let mut goals = Vec::new(); let mut goals = Vec::new();
self.infcx.add_item_bounds_for_hidden_type( self.infcx.add_item_bounds_for_hidden_type(
@ -962,10 +946,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// current inference context. // current inference context.
pub(super) fn unify_existing_opaque_tys( pub(super) fn unify_existing_opaque_tys(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
key: ty::OpaqueTypeKey<'tcx>, key: ty::OpaqueTypeKey<I>,
ty: Ty<'tcx>, ty: I::Ty,
) -> Vec<CanonicalResponse<'tcx>> { ) -> Vec<CanonicalResponse<I>> {
// FIXME: Super inefficient to be cloning this... // FIXME: Super inefficient to be cloning this...
let opaques = self.infcx.clone_opaque_types_for_query_response(); 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.eq(param_env, candidate_ty, ty)?;
ecx.add_item_bounds_for_hidden_type( ecx.add_item_bounds_for_hidden_type(
candidate_key.def_id.to_def_id(), candidate_key.def_id.into(),
candidate_key.args, candidate_key.args,
param_env, param_env,
candidate_ty, candidate_ty,
@ -1001,23 +985,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// as an ambiguity rather than no-solution. // as an ambiguity rather than no-solution.
pub(super) fn try_const_eval_resolve( pub(super) fn try_const_eval_resolve(
&self, &self,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
unevaluated: ty::UnevaluatedConst<'tcx>, unevaluated: ty::UnevaluatedConst<I>,
) -> Option<ty::Const<'tcx>> { ) -> Option<I::Const> {
use rustc_middle::mir::interpret::ErrorHandled; self.infcx.try_const_eval_resolve(param_env, unevaluated)
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()))
}
}
} }
} }
@ -1030,7 +1001,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
struct ReplaceAliasWithInfer<'me, 'a, Infcx, I> struct ReplaceAliasWithInfer<'me, 'a, Infcx, I>
where where
Infcx: IrSolverDelegate<Interner = I>, Infcx: SolverDelegate<Interner = I>,
I: Interner, I: Interner,
{ {
ecx: &'me mut EvalCtxt<'a, Infcx>, ecx: &'me mut EvalCtxt<'a, Infcx>,
@ -1039,7 +1010,7 @@ where
impl<Infcx, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, Infcx, I> impl<Infcx, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, Infcx, I>
where where
Infcx: IrSolverDelegate<Interner = I>, Infcx: SolverDelegate<Interner = I>,
I: Interner, I: Interner,
{ {
fn interner(&self) -> I { fn interner(&self) -> I {
@ -1048,16 +1019,16 @@ where
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
match ty.kind() { 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 infer_ty = self.ecx.next_ty_infer();
let normalizes_to = ir::PredicateKind::AliasRelate( let normalizes_to = ty::PredicateKind::AliasRelate(
ty.into(), ty.into(),
infer_ty.into(), infer_ty.into(),
AliasRelationDirection::Equate, ty::AliasRelationDirection::Equate,
); );
self.ecx.add_goal( self.ecx.add_goal(
GoalSource::Misc, GoalSource::Misc,
ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), Goal::new(self.interner(), self.param_env, normalizes_to),
); );
infer_ty infer_ty
} }
@ -1067,16 +1038,16 @@ where
fn fold_const(&mut self, ct: I::Const) -> I::Const { fn fold_const(&mut self, ct: I::Const) -> I::Const {
match ct.kind() { 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 infer_ct = self.ecx.next_const_infer();
let normalizes_to = ir::PredicateKind::AliasRelate( let normalizes_to = ty::PredicateKind::AliasRelate(
ct.into(), ct.into(),
infer_ct.into(), infer_ct.into(),
AliasRelationDirection::Equate, ty::AliasRelationDirection::Equate,
); );
self.ecx.add_goal( self.ecx.add_goal(
GoalSource::Misc, GoalSource::Misc,
ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), Goal::new(self.interner(), self.param_env, normalizes_to),
); );
infer_ct 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 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> pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T>
where where
Infcx: SolverDelegate<Interner = I>, Infcx: SolverDelegate<Interner = I>,

View file

@ -3,18 +3,20 @@
//! This code is *a bit* of a mess and can hopefully be //! This code is *a bit* of a mess and can hopefully be
//! mostly ignored. For a general overview of how it works, //! mostly ignored. For a general overview of how it works,
//! see the comment on [ProofTreeBuilder]. //! see the comment on [ProofTreeBuilder].
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; 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 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. /// The core data structure when building proof trees.
/// ///
/// In case the current evaluation does not generate a proof /// 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 { for _ in 0..self.probe_depth {
match current.steps.last_mut() { match current.steps.last_mut() {
Some(WipProbeStep::NestedProbe(p)) => current = p, Some(WipProbeStep::NestedProbe(p)) => current = p,
_ => bug!(), _ => panic!(),
} }
} }
current current
@ -294,15 +296,15 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
&mut self, &mut self,
goal: Goal<I, I::Predicate>, goal: Goal<I, I::Predicate>,
orig_values: &[I::GenericArg], orig_values: &[I::GenericArg],
kind: solve::GoalEvaluationKind, kind: GoalEvaluationKind,
) -> ProofTreeBuilder<Infcx> { ) -> ProofTreeBuilder<Infcx> {
self.opt_nested(|| match kind { self.opt_nested(|| match kind {
solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation { GoalEvaluationKind::Root => Some(WipGoalEvaluation {
uncanonicalized_goal: goal, uncanonicalized_goal: goal,
orig_values: orig_values.to_vec(), orig_values: orig_values.to_vec(),
evaluation: None, 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)) => { Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
state.var_values.push(arg.into()); 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; 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); let prev = state.current_evaluation_scope().kind.replace(probe_kind);
assert_eq!(prev, None); 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); let prev = state.current_evaluation_scope().final_state.replace(final_state);
assert_eq!(prev, None); 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)) 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 }); .push(WipProbeStep::RecordImplArgs { impl_args });
} }
None => {} None => {}
_ => bug!(), _ => panic!(),
} }
} }
@ -532,7 +534,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
.push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty });
} }
None => {} None => {}
_ => bug!(), _ => panic!(),
} }
} }
@ -545,7 +547,7 @@ impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
state.var_values.truncate(num_var_values); state.var_values.truncate(num_var_values);
state.probe_depth -= 1; state.probe_depth -= 1;
} }
_ => bug!(), _ => panic!(),
} }
self 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 //! FIXME(@lcnr): Write that section. If you read this before then ask me
//! about it on zulip. //! 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 alias_relate;
mod assembly; mod assembly;
mod eval_ctxt; mod eval_ctxt;
mod fulfill;
mod infcx;
pub mod inspect; pub mod inspect;
mod normalize;
mod normalizes_to; mod normalizes_to;
mod project_goals; mod project_goals;
mod search_graph; mod search_graph;
mod select;
mod trait_goals; mod trait_goals;
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt}; pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt};
pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub use rustc_type_ir::solve::*;
pub(crate) use normalize::deeply_normalize_for_diagnostics;
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; use rustc_type_ir::inherent::*;
pub use select::InferCtxtSelectExt; 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 /// How many fixpoint iterations we should attempt inside of the solver before bailing
/// with overflow. /// with overflow.
@ -66,21 +48,24 @@ enum GoalEvaluationKind {
Nested, Nested,
} }
#[extension(trait CanonicalResponseExt)] fn has_no_inference_or_external_constraints<I: Interner>(
impl<'tcx> Canonical<'tcx, Response<TyCtxt<'tcx>>> { response: ty::Canonical<I, Response<I>>,
fn has_no_inference_or_external_constraints(&self) -> bool { ) -> bool {
self.value.external_constraints.region_constraints.is_empty() response.value.external_constraints.region_constraints.is_empty()
&& self.value.var_values.is_identity() && response.value.var_values.is_identity()
&& self.value.external_constraints.opaque_types.is_empty() && 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))] #[instrument(level = "trace", skip(self))]
fn compute_type_outlives_goal( fn compute_type_outlives_goal(
&mut self, &mut self,
goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, goal: Goal<I, ty::OutlivesPredicate<I, I::Ty>>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let ty::OutlivesPredicate(ty, lt) = goal.predicate; let ty::OutlivesPredicate(ty, lt) = goal.predicate;
self.register_ty_outlives(ty, lt); self.register_ty_outlives(ty, lt);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) 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))] #[instrument(level = "trace", skip(self))]
fn compute_region_outlives_goal( fn compute_region_outlives_goal(
&mut self, &mut self,
goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, goal: Goal<I, ty::OutlivesPredicate<I, I::Region>>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let ty::OutlivesPredicate(a, b) = goal.predicate; let ty::OutlivesPredicate(a, b) = goal.predicate;
self.register_region_outlives(a, b); self.register_region_outlives(a, b);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} }
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
fn compute_coerce_goal( fn compute_coerce_goal(&mut self, goal: Goal<I, ty::CoercePredicate<I>>) -> QueryResult<I> {
&mut self,
goal: Goal<'tcx, CoercePredicate<'tcx>>,
) -> QueryResult<'tcx> {
self.compute_subtype_goal(Goal { self.compute_subtype_goal(Goal {
param_env: goal.param_env, param_env: goal.param_env,
predicate: SubtypePredicate { predicate: ty::SubtypePredicate {
a_is_expected: false, a_is_expected: false,
a: goal.predicate.a, a: goal.predicate.a,
b: goal.predicate.b, b: goal.predicate.b,
@ -112,10 +94,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
} }
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
fn compute_subtype_goal( fn compute_subtype_goal(&mut self, goal: Goal<I, ty::SubtypePredicate<I>>) -> QueryResult<I> {
&mut self,
goal: Goal<'tcx, SubtypePredicate<'tcx>>,
) -> QueryResult<'tcx> {
if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() { if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
} else { } 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> { fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult<I> {
if self.interner().is_object_safe(trait_def_id) { if self.interner().trait_is_object_safe(trait_def_id) {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else { } else {
Err(NoSolution) Err(NoSolution)
@ -133,10 +112,7 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
} }
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
fn compute_well_formed_goal( fn compute_well_formed_goal(&mut self, goal: Goal<I, I::GenericArg>) -> QueryResult<I> {
&mut self,
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
) -> QueryResult<'tcx> {
match self.well_formed_goals(goal.param_env, goal.predicate) { match self.well_formed_goals(goal.param_env, goal.predicate) {
Some(goals) => { Some(goals) => {
self.add_goals(GoalSource::Misc, goals); self.add_goals(GoalSource::Misc, goals);
@ -149,8 +125,8 @@ impl<'a, 'tcx> EvalCtxt<'a, SolverDelegate<'tcx>> {
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
fn compute_const_evaluatable_goal( fn compute_const_evaluatable_goal(
&mut self, &mut self,
Goal { param_env, predicate: ct }: Goal<'tcx, ty::Const<'tcx>>, Goal { param_env, predicate: ct }: Goal<I, I::Const>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
match ct.kind() { match ct.kind() {
ty::ConstKind::Unevaluated(uv) => { ty::ConstKind::Unevaluated(uv) => {
// We never return `NoSolution` here as `try_const_eval_resolve` emits an // 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 // - `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 // - `Expr` is part of `feature(generic_const_exprs)` and is not implemented yet
ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Expr(_) => { 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)] #[instrument(level = "trace", skip(self), ret)]
fn compute_const_arg_has_type_goal( fn compute_const_arg_has_type_goal(
&mut self, &mut self,
goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>, goal: Goal<I, (I::Const, I::Ty)>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let (ct, ty) = goal.predicate; let (ct, ty) = goal.predicate;
let ct_ty = match ct.kind() { 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); return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
} }
ty::ConstKind::Unevaluated(uv) => { 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!( ty::ConstKind::Expr(_) => unimplemented!(
"`feature(generic_const_exprs)` is not supported in the new trait solver" "`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(_) => { ty::ConstKind::Param(_) => {
unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`") 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::Value(ty, _) => ty,
ty::ConstKind::Placeholder(placeholder) => { 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`. /// 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]`. /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
fn try_merge_responses( fn try_merge_responses(
&mut self, &mut self,
responses: &[CanonicalResponse<'tcx>], responses: &[CanonicalResponse<I>],
) -> Option<CanonicalResponse<'tcx>> { ) -> Option<CanonicalResponse<I>> {
if responses.is_empty() { if responses.is_empty() {
return None; return None;
} }
@ -250,14 +230,14 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
.iter() .iter()
.find(|response| { .find(|response| {
response.value.certainty == Certainty::Yes response.value.certainty == Certainty::Yes
&& response.has_no_inference_or_external_constraints() && has_no_inference_or_external_constraints(**response)
}) })
.copied() .copied()
} }
/// If we fail to merge responses we flounder and return overflow or ambiguity. /// If we fail to merge responses we flounder and return overflow or ambiguity.
#[instrument(level = "trace", skip(self), ret)] #[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() { if responses.is_empty() {
return Err(NoSolution); return Err(NoSolution);
} }
@ -267,7 +247,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
certainty.unify_with(response.value.certainty) certainty.unify_with(response.value.certainty)
}) })
else { else {
bug!("expected flounder response to be ambiguous") panic!("expected flounder response to be ambiguous")
}; };
Ok(self.make_ambiguous_response_no_constraints(maybe_cause)) 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)] #[instrument(level = "trace", skip(self, param_env), ret)]
fn structurally_normalize_ty( fn structurally_normalize_ty(
&mut self, &mut self,
param_env: ty::ParamEnv<'tcx>, param_env: I::ParamEnv,
ty: Ty<'tcx>, ty: I::Ty,
) -> Result<Ty<'tcx>, NoSolution> { ) -> Result<I::Ty, NoSolution> {
if let ty::Alias(..) = ty.kind() { if let ty::Alias(..) = ty.kind() {
let normalized_ty = self.next_ty_infer(); let normalized_ty = self.next_ty_infer();
let alias_relate_goal = Goal::new( let alias_relate_goal = Goal::new(
@ -292,7 +272,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
ty::PredicateKind::AliasRelate( ty::PredicateKind::AliasRelate(
ty.into(), ty.into(),
normalized_ty.into(), normalized_ty.into(),
AliasRelationDirection::Equate, ty::AliasRelationDirection::Equate,
), ),
); );
self.add_goal(GoalSource::Misc, alias_relate_goal); self.add_goal(GoalSource::Misc, alias_relate_goal);
@ -306,15 +286,15 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
fn response_no_constraints_raw<I: Interner>( fn response_no_constraints_raw<I: Interner>(
tcx: I, tcx: I,
max_universe: UniverseIndex, max_universe: ty::UniverseIndex,
variables: I::CanonicalVars, variables: I::CanonicalVars,
certainty: Certainty, certainty: Certainty,
) -> ir::solve::CanonicalResponse<I> { ) -> CanonicalResponse<I> {
ir::Canonical { ty::Canonical {
max_universe, max_universe,
variables, variables,
value: Response { 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 // FIXME: maybe we should store the "no response" version in tcx, like
// we do for tcx.types and stuff. // we do for tcx.types and stuff.
external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()), external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()),

View file

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

View file

@ -5,17 +5,20 @@
//! 2. equate the self type, and //! 2. equate the self type, and
//! 3. instantiate and register where clauses. //! 3. instantiate and register where clauses.
use crate::solve::infcx::SolverDelegate; use rustc_type_ir::{self as ty, Interner};
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
use rustc_middle::ty;
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( pub(super) fn normalize_inherent_associated_type(
&mut self, &mut self,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, goal: Goal<I, ty::NormalizesTo<I>>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let tcx = self.interner(); let tcx = self.interner();
let inherent = goal.predicate.alias.expect_ty(tcx); let inherent = goal.predicate.alias.expect_ty(tcx);
@ -26,7 +29,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
self.eq( self.eq(
goal.param_env, goal.param_env,
inherent.self_ty(), 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 // Equate IAT with the RHS of the project goal
@ -41,12 +44,11 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
self.add_goals( self.add_goals(
GoalSource::Misc, GoalSource::Misc,
tcx.predicates_of(inherent.def_id) tcx.predicates_of(inherent.def_id)
.instantiate(tcx, inherent_args) .iter_instantiated(tcx, &inherent_args)
.into_iter() .map(|pred| goal.with(tcx, pred)),
.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.instantiate_normalizes_to_term(goal, normalized.into());
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) 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 anon_const;
mod inherent; mod inherent;
mod opaque_types; mod opaque_types;
mod weak_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)] #[instrument(level = "trace", skip(self), ret)]
pub(super) fn compute_normalizes_to_goal( pub(super) fn compute_normalizes_to_goal(
&mut self, &mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>, goal: Goal<I, NormalizesTo<I>>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
self.set_is_normalizes_to_goal(); self.set_is_normalizes_to_goal();
debug_assert!(self.term_is_fully_unconstrained(goal)); debug_assert!(self.term_is_fully_unconstrained(goal));
let normalize_result = self 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 /// Normalize the given alias by at least one step. If the alias is rigid, this
/// returns `NoSolution`. /// returns `NoSolution`.
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
fn normalize_at_least_one_step( fn normalize_at_least_one_step(&mut self, goal: Goal<I, NormalizesTo<I>>) -> QueryResult<I> {
&mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>,
) -> QueryResult<'tcx> {
match goal.predicate.alias.kind(self.interner()) { match goal.predicate.alias.kind(self.interner()) {
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
let candidates = self.assemble_and_evaluate_candidates(goal); 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. /// emit nested `AliasRelate` goals to structurally normalize the alias.
pub fn instantiate_normalizes_to_term( pub fn instantiate_normalizes_to_term(
&mut self, &mut self,
goal: Goal<'tcx, NormalizesTo<'tcx>>, goal: Goal<I, NormalizesTo<I>>,
term: ty::Term<'tcx>, term: I::Term,
) { ) {
self.eq(goal.param_env, goal.predicate.term, term) self.eq(goal.param_env, goal.predicate.term, term)
.expect("expected goal term to be fully unconstrained"); .expect("expected goal term to be fully unconstrained");
} }
} }
impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { impl<Infcx, I> assembly::GoalKind<Infcx> for NormalizesTo<I>
fn self_ty(self) -> Ty<'tcx> { where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
fn self_ty(self) -> I::Ty {
self.self_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) 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) 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) self.trait_def_id(tcx)
} }
fn probe_and_match_goal_against_assumption( fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
source: CandidateSource<'tcx>, source: CandidateSource<I>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
assumption: ty::Clause<'tcx>, assumption: I::Clause,
then: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>) -> QueryResult<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if let Some(projection_pred) = assumption.as_projection_clause() { if let Some(projection_pred) = assumption.as_projection_clause() {
if projection_pred.projection_def_id() == goal.predicate.def_id() { if projection_pred.projection_def_id() == goal.predicate.def_id() {
let tcx = ecx.interner(); 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 // Add GAT where clauses from the trait's definition
ecx.add_goals( ecx.add_goals(
GoalSource::Misc, GoalSource::Misc,
tcx.predicates_of(goal.predicate.def_id()) tcx.own_predicates_of(goal.predicate.def_id())
.instantiate_own(tcx, goal.predicate.alias.args) .iter_instantiated(tcx, &goal.predicate.alias.args)
.map(|(pred, _)| goal.with(tcx, pred)), .map(|pred| goal.with(tcx, pred)),
); );
then(ecx) then(ecx)
@ -137,24 +135,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
} }
fn consider_impl_candidate( fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, NormalizesTo<'tcx>>, goal: Goal<I, NormalizesTo<I>>,
impl_def_id: DefId, impl_def_id: I::DefId,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner(); let tcx = ecx.interner();
let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx);
let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; if !ecx.interner().args_may_unify_deep(
if !drcx.args_may_unify( goal.predicate.alias.trait_ref(tcx).args,
goal.predicate.trait_ref(tcx).args, impl_trait_ref.skip_binder().args,
impl_trait_header.trait_ref.skip_binder().args,
) { ) {
return Err(NoSolution); return Err(NoSolution);
} }
// We have to ignore negative impls when projecting. // 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 { match impl_polarity {
ty::ImplPolarity::Negative => return Err(NoSolution), ty::ImplPolarity::Negative => return Err(NoSolution),
ty::ImplPolarity::Reservation => { 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| { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
let impl_args = ecx.fresh_args_for_item(impl_def_id); 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)?; ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
let where_clause_bounds = tcx let where_clause_bounds = tcx
.predicates_of(impl_def_id) .predicates_of(impl_def_id)
.instantiate(tcx, impl_args) .iter_instantiated(tcx, &impl_args)
.predicates
.into_iter()
.map(|pred| goal.with(tcx, pred)); .map(|pred| goal.with(tcx, pred));
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
// Add GAT where clauses from the trait's definition // Add GAT where clauses from the trait's definition
ecx.add_goals( ecx.add_goals(
GoalSource::Misc, GoalSource::Misc,
tcx.predicates_of(goal.predicate.def_id()) tcx.own_predicates_of(goal.predicate.def_id())
.instantiate_own(tcx, goal.predicate.alias.args) .iter_instantiated(tcx, &goal.predicate.alias.args)
.map(|(pred, _)| goal.with(tcx, pred)), .map(|pred| goal.with(tcx, pred)),
); );
// In case the associated item is hidden due to specialization, we have to // In case the associated item is hidden due to specialization, we have to
// return ambiguity this would otherwise be incomplete, resulting in // return ambiguity this would otherwise be incomplete, resulting in
// unsoundness during coherence (#105782). // 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.param_env,
goal_trait_ref, goal_trait_ref,
goal.predicate.def_id(), 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); return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
}; };
let error_response = |ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, reason| { let error_response = |ecx: &mut EvalCtxt<'_, Infcx>, msg: &str| {
let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason); let guar = tcx.delay_bug(msg);
let error_term = match goal.predicate.alias.kind(tcx) { let error_term = match goal.predicate.alias.kind(tcx) {
ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(), ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(),
ty::AliasTermKind::ProjectionConst => ty::Const::new_error(tcx, guar).into(), ty::AliasTermKind::ProjectionConst => Const::new_error(tcx, guar).into(),
kind => bug!("expected projection, found {kind:?}"), kind => panic!("expected projection, found {kind:?}"),
}; };
ecx.instantiate_normalizes_to_term(goal, error_term); ecx.instantiate_normalizes_to_term(goal, error_term);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}; };
if !assoc_def.item.defaultness(tcx).has_value() { if !tcx.has_item_definition(target_item_def_id) {
return error_response(ecx, "missing value for assoc item in impl"); 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: // Getting the right args here is complex, e.g. given:
// - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>` // - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>`
// - the applicable impl `impl<T> Trait<i32> for Vec<T>` // - 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 // And then map these args to the args of the defining impl of `Assoc`, going
// from `[u32, u64]` to `[u32, i32, u64]`. // from `[u32, u64]` to `[u32, i32, u64]`.
let associated_item_args = let target_args = ecx.translate_args(
ecx.translate_args(&assoc_def, goal, impl_def_id, impl_args, impl_trait_ref)?; 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) { if !tcx.check_args_compatible(target_item_def_id, target_args) {
return error_response( return error_response(ecx, "associated item has mismatched arguments");
ecx,
"associated item has mismatched generic item arguments",
);
} }
// Finally we construct the actual value of the associated type. // Finally we construct the actual value of the associated type.
let term = match goal.predicate.alias.kind(tcx) { let term = match goal.predicate.alias.kind(tcx) {
ty::AliasTermKind::ProjectionTy => { 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 => { ty::AliasTermKind::ProjectionConst => {
if tcx.features().associated_const_equality { if tcx.features().associated_const_equality() {
bug!("associated const projection is not supported yet") panic!("associated const projection is not supported yet")
} else { } else {
ty::EarlyBinder::bind( ty::EarlyBinder::bind(
ty::Const::new_error_with_message( Const::new_error_with_message(
tcx, tcx,
DUMMY_SP,
"associated const projection is not supported yet", "associated const projection is not supported yet",
) )
.into(), .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) 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` /// 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. /// and succeed. Can experiment with this to figure out what results in better error messages.
fn consider_error_guaranteed_candidate( fn consider_error_guaranteed_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
_guar: ErrorGuaranteed, _guar: I::ErrorGuaranteed,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
Err(NoSolution) Err(NoSolution)
} }
fn consider_auto_trait_candidate( fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, _goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
ecx.interner().dcx().span_delayed_bug( ecx.interner().delay_bug("associated types not allowed on auto traits");
ecx.interner().def_span(goal.predicate.def_id()),
"associated types not allowed on auto traits",
);
Err(NoSolution) Err(NoSolution)
} }
fn consider_trait_alias_candidate( fn consider_trait_alias_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("trait aliases do not have associated types: {:?}", goal); panic!("trait aliases do not have associated types: {:?}", goal);
} }
fn consider_builtin_sized_candidate( fn consider_builtin_sized_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("`Sized` does not have an associated type: {:?}", goal); panic!("`Sized` does not have an associated type: {:?}", goal);
} }
fn consider_builtin_copy_clone_candidate( fn consider_builtin_copy_clone_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
} }
fn consider_builtin_pointer_like_candidate( fn consider_builtin_pointer_like_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("`PointerLike` does not have an associated type: {:?}", goal); panic!("`PointerLike` does not have an associated type: {:?}", goal);
} }
fn consider_builtin_fn_ptr_trait_candidate( fn consider_builtin_fn_ptr_trait_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("`FnPtr` does not have an associated type: {:?}", goal); panic!("`FnPtr` does not have an associated type: {:?}", goal);
} }
fn consider_builtin_fn_trait_candidates( fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
goal_kind: ty::ClosureKind, goal_kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner(); let tcx = ecx.interner();
let tupled_inputs_and_output = let tupled_inputs_and_output =
match structural_traits::extract_tupled_inputs_and_output_from_callable( 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)| { 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 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( fn consider_builtin_async_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
goal_kind: ty::ClosureKind, goal_kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner(); let tcx = ecx.interner();
let env_region = match goal_kind { let env_region = match goal_kind {
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2),
// Doesn't matter what this region is // 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) = let (tupled_inputs_and_output_and_coroutine, nested_preds) =
structural_traits::extract_tupled_inputs_and_output_from_async_callable( 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( let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
|AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { |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, coroutine_return_ty,
}| { }| {
let (projection_term, term) = if tcx 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( ty::AliasTerm::new(
@ -401,34 +400,41 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
), ),
output_coroutine_ty.into(), output_coroutine_ty.into(),
) )
} else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CallRefFuture) { } 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()),
tupled_inputs_ty.into(),
env_region.into(),
],
),
output_coroutine_ty.into(),
)
} else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::AsyncFnOnceOutput)
{ {
( (
ty::AliasTerm::new( ty::AliasTerm::new(
tcx, tcx,
goal.predicate.def_id(), 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(), tupled_inputs_ty.into(),
], ],
), ),
coroutine_return_ty.into(), coroutine_return_ty.into(),
) )
} else { } 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 } 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( fn consider_builtin_async_fn_kind_helper_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let [ let [
closure_fn_kind_ty, closure_fn_kind_ty,
goal_kind_ty, goal_kind_ty,
@ -462,7 +468,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
coroutine_captures_by_ref_ty, coroutine_captures_by_ref_ty,
] = **goal.predicate.alias.args ] = **goal.predicate.alias.args
else { else {
bug!(); panic!();
}; };
// Bail if the upvars haven't been constrained. // 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( fn consider_builtin_tuple_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("`Tuple` does not have an associated type: {:?}", goal); panic!("`Tuple` does not have an associated type: {:?}", goal);
} }
fn consider_builtin_pointee_candidate( fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner(); 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()); assert_eq!(metadata_def_id, goal.predicate.def_id());
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
let metadata_ty = match goal.predicate.self_ty().kind() { let metadata_ty = match goal.predicate.self_ty().kind() {
@ -530,16 +536,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
| ty::CoroutineWitness(..) | ty::CoroutineWitness(..)
| ty::Never | ty::Never
| ty::Foreign(..) | 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) => { 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) 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(..) => { 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`. // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
let sized_predicate = ty::TraitRef::new( let sized_predicate = ty::TraitRef::new(
tcx, tcx,
tcx.require_lang_item(LangItem::Sized, None), tcx.require_lang_item(TraitSolverLangItem::Sized),
[ty::GenericArg::from(goal.predicate.self_ty())], [I::GenericArg::from(goal.predicate.self_ty())],
); );
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate)); 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() { ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(tcx) {
None => tcx.types.unit, None => Ty::new_unit(tcx),
Some(tail_def) => { Some(tail_ty) => {
let tail_ty = tail_def.ty(tcx, args); Ty::new_projection(tcx, metadata_def_id, [tail_ty.instantiate(tcx, &args)])
Ty::new_projection(tcx, metadata_def_id, [tail_ty])
} }
}, },
ty::Adt(_, _) => tcx.types.unit, ty::Adt(_, _) => Ty::new_unit(tcx),
ty::Tuple(elements) => match elements.last() { 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]), Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]),
}, },
ty::Infer( ty::Infer(
ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_), ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
) )
| ty::Bound(..) => bug!( | ty::Bound(..) => panic!(
"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
goal.predicate.self_ty() goal.predicate.self_ty()
), ),
@ -586,11 +591,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
} }
fn consider_builtin_future_candidate( fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty(); 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); return Err(NoSolution);
}; };
@ -622,11 +627,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
} }
fn consider_builtin_iterator_candidate( fn consider_builtin_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty(); 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); return Err(NoSolution);
}; };
@ -658,18 +663,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
} }
fn consider_builtin_fused_iterator_candidate( fn consider_builtin_fused_iterator_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("`FusedIterator` does not have an associated type: {:?}", goal); panic!("`FusedIterator` does not have an associated type: {:?}", goal);
} }
fn consider_builtin_async_iterator_candidate( fn consider_builtin_async_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty(); 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); return Err(NoSolution);
}; };
@ -685,10 +690,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
// coroutine yield ty `Poll<Option<I>>`. // coroutine yield ty `Poll<Option<I>>`.
let wrapped_expected_ty = Ty::new_adt( let wrapped_expected_ty = Ty::new_adt(
tcx, 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.mk_args(&[Ty::new_adt(
tcx, 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()]), tcx.mk_args(&[expected_ty.into()]),
) )
.into()]), .into()]),
@ -701,11 +706,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
} }
fn consider_builtin_coroutine_candidate( fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty(); 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); return Err(NoSolution);
}; };
@ -717,15 +722,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
let coroutine = args.as_coroutine(); 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() 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() coroutine.yield_ty().into()
} else { } else {
bug!( panic!("unexpected associated item `{:?}` for `{self_ty:?}`", goal.predicate.def_id())
"unexpected associated item `<{self_ty} as Coroutine>::{}`",
tcx.item_name(goal.predicate.def_id())
)
}; };
Self::probe_and_consider_implied_clause( Self::probe_and_consider_implied_clause(
@ -748,18 +752,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
} }
fn consider_structural_builtin_unsize_candidates( fn consider_structural_builtin_unsize_candidates(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Vec<Candidate<TyCtxt<'tcx>>> { ) -> Vec<Candidate<I>> {
bug!("`Unsize` does not have an associated type: {:?}", goal); panic!("`Unsize` does not have an associated type: {:?}", goal);
} }
fn consider_builtin_discriminant_kind_candidate( fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty(); let self_ty = goal.predicate.self_ty();
let discriminant_ty = match *self_ty.kind() { let discriminant_ty = match self_ty.kind() {
ty::Bool ty::Bool
| ty::Char | ty::Char
| ty::Int(..) | 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::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!( | ty::Bound(..) => panic!(
"unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`", "unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`",
goal.predicate.self_ty() goal.predicate.self_ty()
), ),
@ -807,11 +811,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
} }
fn consider_builtin_async_destruct_candidate( fn consider_builtin_async_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty(); 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::Bool
| ty::Char | ty::Char
| ty::Int(..) | 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::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Foreign(..) | ty::Foreign(..)
| ty::Bound(..) => bug!( | ty::Bound(..) => panic!(
"unexpected self ty `{:?}` when normalizing `<T as AsyncDestruct>::AsyncDestructor`", "unexpected self ty `{:?}` when normalizing `<T as AsyncDestruct>::AsyncDestructor`",
goal.predicate.self_ty() 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:?}" "`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( fn consider_builtin_destruct_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("`Destruct` does not have an associated type: {:?}", goal); panic!("`Destruct` does not have an associated type: {:?}", goal);
} }
fn consider_builtin_transmute_candidate( fn consider_builtin_transmute_candidate(
_ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) 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( fn translate_args(
&mut self, &mut self,
assoc_def: &LeafDef, goal: Goal<I, ty::NormalizesTo<I>>,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, impl_def_id: I::DefId,
impl_def_id: DefId, impl_args: I::GenericArgs,
impl_args: ty::GenericArgsRef<'tcx>, impl_trait_ref: rustc_type_ir::TraitRef<I>,
impl_trait_ref: rustc_type_ir::TraitRef<TyCtxt<'tcx>>, target_container_def_id: I::DefId,
) -> Result<ty::GenericArgsRef<'tcx>, NoSolution> { ) -> Result<I::GenericArgs, NoSolution> {
let tcx = self.interner(); let tcx = self.interner();
Ok(match assoc_def.defining_node { Ok(if target_container_def_id == impl_trait_ref.def_id {
Node::Trait(_) => goal.predicate.alias.args, // Default value from the trait definition. No need to rebase.
Node::Impl(target_impl_def_id) => { goal.predicate.alias.args
if target_impl_def_id == impl_def_id { } else if target_container_def_id == impl_def_id {
// Same impl, no need to fully translate, just a rebase from // Same impl, no need to fully translate, just a rebase from
// the trait is sufficient. // the trait is sufficient.
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args) goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args)
} else { } else {
let target_args = self.fresh_args_for_item(target_impl_def_id); let target_args = self.fresh_args_for_item(target_container_def_id);
let target_trait_ref = tcx let target_trait_ref =
.impl_trait_ref(target_impl_def_id) tcx.impl_trait_ref(target_container_def_id).instantiate(tcx, &target_args);
.unwrap() // Relate source impl to target impl by equating trait refs.
.instantiate(tcx, target_args); self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?;
// Relate source impl to target impl by equating trait refs. // Also add predicates since they may be needed to constrain the
self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?; // target impl's params.
// Also add predicates since they may be needed to constrain the self.add_goals(
// target impl's params. GoalSource::Misc,
self.add_goals( tcx.predicates_of(target_container_def_id)
GoalSource::Misc, .iter_instantiated(tcx, &target_args)
tcx.predicates_of(target_impl_def_id) .map(|pred| goal.with(tcx, pred)),
.instantiate(tcx, target_args) );
.into_iter() goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, 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 //! behaves differently depending on the param-env's reveal mode and whether
//! the opaque is in a defining scope. //! the opaque is in a defining scope.
use crate::solve::infcx::SolverDelegate; use rustc_index::bit_set::GrowableBitSet;
use rustc_middle::traits::query::NoSolution; use rustc_type_ir::inherent::*;
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_type_ir::{self as ty, Interner};
use rustc_middle::traits::Reveal;
use rustc_middle::ty;
use rustc_middle::ty::util::NotUniqueParam;
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( pub(super) fn normalize_opaque_type(
&mut self, &mut self,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, goal: Goal<I, ty::NormalizesTo<I>>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let tcx = self.interner(); let tcx = self.interner();
let opaque_ty = goal.predicate.alias; let opaque_ty = goal.predicate.alias;
let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); 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); return Err(NoSolution);
} }
// FIXME: This may have issues when the args contain aliases... // 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() => { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
return self.evaluate_added_goals_and_make_canonical_response( return self.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS, Certainty::AMBIGUOUS,
@ -61,6 +63,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
} }
// Otherwise, define a new opaque type // 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.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
self.add_item_bounds_for_hidden_type( self.add_item_bounds_for_hidden_type(
opaque_ty.def_id, opaque_ty.def_id,
@ -83,10 +86,51 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
} }
(Reveal::All, _) => { (Reveal::All, _) => {
// FIXME: Add an assertion that opaque type storage is empty. // 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.eq(goal.param_env, expected, actual)?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) 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 //! 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. //! the alias and registers the where-clauses of the type alias.
use crate::solve::infcx::SolverDelegate; use rustc_type_ir::{self as ty, Interner};
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
use rustc_middle::ty;
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( pub(super) fn normalize_weak_type(
&mut self, &mut self,
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, goal: Goal<I, ty::NormalizesTo<I>>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let tcx = self.interner(); let tcx = self.interner();
let weak_ty = goal.predicate.alias; let weak_ty = goal.predicate.alias;
@ -22,13 +25,11 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
self.add_goals( self.add_goals(
GoalSource::Misc, GoalSource::Misc,
tcx.predicates_of(weak_ty.def_id) tcx.predicates_of(weak_ty.def_id)
.instantiate(tcx, weak_ty.args) .iter_instantiated(tcx, &weak_ty.args)
.predicates
.into_iter()
.map(|pred| goal.with(tcx, pred)), .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.instantiate_normalizes_to_term(goal, actual.into());
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) 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 crate::infcx::SolverDelegate;
use super::EvalCtxt; use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult};
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
use rustc_middle::ty::{self, ProjectionPredicate};
impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> { impl<Infcx, I> EvalCtxt<'_, Infcx>
where
Infcx: SolverDelegate<Interner = I>,
I: Interner,
{
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
pub(super) fn compute_projection_goal( pub(super) fn compute_projection_goal(
&mut self, &mut self,
goal: Goal<'tcx, ProjectionPredicate<'tcx>>, goal: Goal<I, ProjectionPredicate<I>>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let tcx = self.interner(); let tcx = self.interner();
let projection_term = goal.predicate.projection_term.to_term(tcx); let projection_term = goal.predicate.projection_term.to_term(tcx);
let goal = goal.with( let goal = goal.with(

View file

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

View file

@ -1,60 +1,59 @@
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`. //! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
use super::assembly::structural_traits::AsyncCallableRelevantTypes; use rustc_ast_ir::Movability;
use super::assembly::{self, structural_traits, Candidate};
use super::infcx::SolverDelegate;
use super::{EvalCtxt, GoalSource, SolverMode};
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId; use rustc_type_ir::inherent::*;
use rustc_hir::{LangItem, Movability}; use rustc_type_ir::lang_items::TraitSolverLangItem;
use rustc_infer::traits::query::NoSolution; use rustc_type_ir::visit::TypeVisitableExt as _;
use rustc_infer::traits::solve::MaybeCause; use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _};
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;
impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { use crate::infcx::SolverDelegate;
fn self_ty(self) -> Ty<'tcx> { 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() self.self_ty()
} }
fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> { fn trait_ref(self, _: I) -> ty::TraitRef<I> {
self.trait_ref 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) 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() self.def_id()
} }
fn consider_impl_candidate( fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, TraitPredicate<'tcx>>, goal: Goal<I, TraitPredicate<I>>,
impl_def_id: DefId, impl_def_id: I::DefId,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let tcx = ecx.interner(); let tcx = ecx.interner();
let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; if !tcx
if !drcx.args_may_unify( .args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
goal.predicate.trait_ref.args, {
impl_trait_header.trait_ref.skip_binder().args,
) {
return Err(NoSolution); return Err(NoSolution);
} }
// An upper bound of the certainty of this goal, used to lower the certainty // An upper bound of the certainty of this goal, used to lower the certainty
// of reservation impl to ambiguous during coherence. // 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) { let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
// In intercrate mode, this is ambiguous. But outside of intercrate, // In intercrate mode, this is ambiguous. But outside of intercrate,
// it's not a real impl. // 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| { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
let impl_args = ecx.fresh_args_for_item(impl_def_id); let impl_args = ecx.fresh_args_for_item(impl_def_id);
ecx.record_impl_args(impl_args); 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)?; ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
let where_clause_bounds = tcx let where_clause_bounds = tcx
.predicates_of(impl_def_id) .predicates_of(impl_def_id)
.instantiate(tcx, impl_args) .iter_instantiated(tcx, &impl_args)
.predicates
.into_iter()
.map(|pred| goal.with(tcx, pred)); .map(|pred| goal.with(tcx, pred));
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); 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( fn consider_error_guaranteed_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
_guar: ErrorGuaranteed, _guar: I::ErrorGuaranteed,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
// FIXME: don't need to enter a probe here. // FIXME: don't need to enter a probe here.
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
} }
fn probe_and_match_goal_against_assumption( fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
source: CandidateSource<'tcx>, source: CandidateSource<I>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
assumption: ty::Clause<'tcx>, assumption: I::Clause,
then: impl FnOnce(&mut EvalCtxt<'_, SolverDelegate<'tcx>>) -> QueryResult<'tcx>, then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if let Some(trait_clause) = assumption.as_trait_clause() { if let Some(trait_clause) = assumption.as_trait_clause() {
if trait_clause.def_id() == goal.predicate.def_id() if trait_clause.def_id() == goal.predicate.def_id()
&& trait_clause.polarity() == goal.predicate.polarity && trait_clause.polarity() == goal.predicate.polarity
@ -130,9 +127,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_auto_trait_candidate( fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); 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 let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
if matches!(goal.param_env.reveal(), Reveal::All) if matches!(goal.param_env.reveal(), Reveal::All)
|| matches!(ecx.solver_mode(), SolverMode::Coherence) || 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); return Err(NoSolution);
} }
@ -173,9 +173,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_trait_alias_candidate( fn consider_trait_alias_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -185,20 +185,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
let nested_obligations = tcx let nested_obligations = tcx
.predicates_of(goal.predicate.def_id()) .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`? // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
ecx.add_goals( ecx.add_goals(GoalSource::Misc, nested_obligations);
GoalSource::Misc,
nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)),
);
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}) })
} }
fn consider_builtin_sized_candidate( fn consider_builtin_sized_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -211,9 +209,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_copy_clone_candidate( fn consider_builtin_copy_clone_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -226,28 +224,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_pointer_like_candidate( fn consider_builtin_pointer_like_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
// The regions of a type don't affect the size of the type
let tcx = ecx.interner(); 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. // 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); return ecx.forced_ambiguity(MaybeCause::Ambiguity);
} }
if let Ok(layout) = tcx.layout_of(key) if tcx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) {
&& layout.layout.is_pointer_like(&tcx.data_layout)
{
// FIXME: We could make this faster by making a no-constraints response
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
} else { } else {
@ -256,9 +246,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_fn_ptr_trait_candidate( fn consider_builtin_fn_ptr_trait_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let self_ty = goal.predicate.self_ty(); let self_ty = goal.predicate.self_ty();
match goal.predicate.polarity { match goal.predicate.polarity {
// impl FnPtr for FnPtr {} // impl FnPtr for FnPtr {}
@ -287,10 +277,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_fn_trait_candidates( fn consider_builtin_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
goal_kind: ty::ClosureKind, goal_kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); 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)| { 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 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( fn consider_builtin_async_fn_trait_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
goal_kind: ty::ClosureKind, goal_kind: ty::ClosureKind,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -343,13 +333,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
goal.predicate.self_ty(), goal.predicate.self_ty(),
goal_kind, goal_kind,
// This region doesn't matter because we're throwing away the coroutine type // 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( let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
|AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
ty::TraitRef::new( ty::TraitRef::new(
tcx, tcx,
tcx.require_lang_item(LangItem::Sized, None), tcx.require_lang_item(TraitSolverLangItem::Sized),
[output_coroutine_ty], [output_coroutine_ty],
) )
}, },
@ -379,11 +369,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_async_fn_kind_helper_candidate( fn consider_builtin_async_fn_kind_helper_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else { 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 { 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) {} /// impl Tuple for (T1, .., Tn) {}
/// ``` /// ```
fn consider_builtin_tuple_candidate( fn consider_builtin_tuple_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -422,9 +412,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_pointee_candidate( fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -434,14 +424,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_future_candidate( fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); 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); return Err(NoSolution);
}; };
@ -460,14 +450,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_iterator_candidate( fn consider_builtin_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); 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); return Err(NoSolution);
}; };
@ -486,14 +476,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_fused_iterator_candidate( fn consider_builtin_fused_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); 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); return Err(NoSolution);
}; };
@ -510,14 +500,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_async_iterator_candidate( fn consider_builtin_async_iterator_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); 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); return Err(NoSolution);
}; };
@ -536,15 +526,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_coroutine_candidate( fn consider_builtin_coroutine_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
let self_ty = goal.predicate.self_ty(); 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); return Err(NoSolution);
}; };
@ -568,9 +558,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_discriminant_kind_candidate( fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -581,9 +571,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_async_destruct_candidate( fn consider_builtin_async_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -594,9 +584,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_destruct_candidate( fn consider_builtin_destruct_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -610,10 +600,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
} }
fn consider_builtin_transmute_candidate( fn consider_builtin_transmute_candidate(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, _ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, _goal: Goal<I, Self>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { // TODO:
todo!()
/* if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution); return Err(NoSolution);
} }
@ -641,6 +633,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
)?; )?;
ecx.evaluate_added_goals_and_make_canonical_response(certainty) ecx.evaluate_added_goals_and_make_canonical_response(certainty)
}) })
*/
} }
/// ```ignore (builtin impl example) /// ```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 {} /// impl<'a, T: Trait + 'a> Unsize<dyn Trait + 'a> for T {}
/// ``` /// ```
fn consider_structural_builtin_unsize_candidates( fn consider_structural_builtin_unsize_candidates(
ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, ecx: &mut EvalCtxt<'_, Infcx>,
goal: Goal<'tcx, Self>, goal: Goal<I, Self>,
) -> Vec<Candidate<TyCtxt<'tcx>>> { ) -> Vec<Candidate<I>> {
if goal.predicate.polarity != ty::PredicatePolarity::Positive { if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return vec![]; return vec![];
} }
@ -676,7 +669,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
let goal = goal.with(ecx.interner(), (a_ty, b_ty)); let goal = goal.with(ecx.interner(), (a_ty, b_ty));
match (a_ty.kind(), b_ty.kind()) { 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(..))) => { (_, ty::Infer(ty::TyVar(..))) => {
result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity)) 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`. // Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
( (
&ty::Dynamic(a_data, a_region, ty::Dyn), ty::Dynamic(a_data, a_region, ty::Dyn),
&ty::Dynamic(b_data, b_region, ty::Dyn), ty::Dynamic(b_data, b_region, ty::Dyn),
) => ecx.consider_builtin_dyn_upcast_candidates( ) => ecx.consider_builtin_dyn_upcast_candidates(
goal, a_data, a_region, b_data, b_region, goal, a_data, a_region, b_data, b_region,
), ),
// `T` -> `dyn Trait` unsizing. // `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), ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
), ),
// `[T; N]` -> `[T]` unsizing // `[T; N]` -> `[T]` unsizing
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => { (ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, 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>` // `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 => if a_def.is_struct() && a_def == b_def =>
{ {
result_to_single( 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>` // `(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() => if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
{ {
result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys)) 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: /// Trait upcasting allows for coercions between trait objects:
/// ```ignore (builtin impl example) /// ```ignore (builtin impl example)
/// trait Super {} /// trait Super {}
@ -734,12 +731,12 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// ``` /// ```
fn consider_builtin_dyn_upcast_candidates( fn consider_builtin_dyn_upcast_candidates(
&mut self, &mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, goal: Goal<I, (I::Ty, I::Ty)>,
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, a_data: I::BoundExistentialPredicates,
a_region: ty::Region<'tcx>, a_region: I::Region,
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, b_data: I::BoundExistentialPredicates,
b_region: ty::Region<'tcx>, b_region: I::Region,
) -> Vec<Candidate<TyCtxt<'tcx>>> { ) -> Vec<Candidate<I>> {
let tcx = self.interner(); let tcx = self.interner();
let Goal { predicate: (a_ty, _b_ty), .. } = goal; let Goal { predicate: (a_ty, _b_ty), .. } = goal;
@ -757,7 +754,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
a_data.principal(), a_data.principal(),
)); ));
} else if let Some(a_principal) = 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( responses.extend(self.consider_builtin_upcast_to_principal(
goal, goal,
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting), CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
@ -777,15 +777,15 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
fn consider_builtin_unsize_to_dyn_candidate( fn consider_builtin_unsize_to_dyn_candidate(
&mut self, &mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, goal: Goal<I, (I::Ty, I::Ty)>,
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, b_data: I::BoundExistentialPredicates,
b_region: ty::Region<'tcx>, b_region: I::Region,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let tcx = self.interner(); let tcx = self.interner();
let Goal { predicate: (a_ty, _), .. } = goal; let Goal { predicate: (a_ty, _), .. } = goal;
// Can only unsize to an object-safe trait. // 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); 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) // (i.e. the principal, all of the associated types match, and any auto traits)
ecx.add_goals( ecx.add_goals(
GoalSource::ImplWhereBound, 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. // The type must be `Sized` to be unsized.
@ -802,7 +802,11 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
GoalSource::ImplWhereBound, GoalSource::ImplWhereBound,
goal.with( goal.with(
tcx, 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( fn consider_builtin_upcast_to_principal(
&mut self, &mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, goal: Goal<I, (I::Ty, I::Ty)>,
source: CandidateSource<'tcx>, source: CandidateSource<I>,
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, a_data: I::BoundExistentialPredicates,
a_region: ty::Region<'tcx>, a_region: I::Region,
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, b_data: I::BoundExistentialPredicates,
b_region: ty::Region<'tcx>, b_region: I::Region,
upcast_principal: Option<ty::PolyExistentialTraitRef<'tcx>>, upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let param_env = goal.param_env; let param_env = goal.param_env;
// We may upcast to auto traits that are either explicitly listed in // 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 // the object type's bounds, or implied by the principal trait ref's
// supertraits. // supertraits.
let a_auto_traits: FxIndexSet<DefId> = a_data let a_auto_traits: FxIndexSet<I::DefId> = a_data
.auto_traits() .auto_traits()
.into_iter()
.chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
self.interner() self.interner()
.supertrait_def_ids(principal_def_id) .supertrait_def_ids(principal_def_id)
.into_iter()
.filter(|def_id| self.interner().trait_is_auto(*def_id)) .filter(|def_id| self.interner().trait_is_auto(*def_id))
})) }))
.collect(); .collect();
@ -841,9 +847,9 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// having any inference side-effects. We process obligations because // having any inference side-effects. We process obligations because
// unification may initially succeed due to deferred projection equality. // unification may initially succeed due to deferred projection equality.
let projection_may_match = let projection_may_match =
|ecx: &mut EvalCtxt<'_, SolverDelegate<'tcx>>, |ecx: &mut EvalCtxt<'_, Infcx>,
source_projection: ty::PolyExistentialProjection<'tcx>, source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
target_projection: ty::PolyExistentialProjection<'tcx>| { target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
source_projection.item_def_id() == target_projection.item_def_id() source_projection.item_def_id() == target_projection.item_def_id()
&& ecx && ecx
.probe(|_| ProbeKind::UpcastProjectionCompatibility) .probe(|_| ProbeKind::UpcastProjectionCompatibility)
@ -875,7 +881,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
ty::ExistentialPredicate::Projection(target_projection) => { ty::ExistentialPredicate::Projection(target_projection) => {
let target_projection = bound.rebind(target_projection); let target_projection = bound.rebind(target_projection);
let mut matching_projections = 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) projection_may_match(ecx, *source_projection, target_projection)
}); });
let Some(source_projection) = matching_projections.next() else { 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. // Also require that a_ty's lifetime outlives b_ty's lifetime.
ecx.add_goal( ecx.add_goal(
GoalSource::ImplWhereBound, GoalSource::ImplWhereBound,
Goal::new( Goal::new(ecx.interner(), param_env, ty::OutlivesPredicate(a_region, b_region)),
ecx.interner(),
param_env,
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
),
); );
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
@ -921,10 +923,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// `#[rustc_deny_explicit_impl]` in this case. /// `#[rustc_deny_explicit_impl]` in this case.
fn consider_builtin_array_unsize( fn consider_builtin_array_unsize(
&mut self, &mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, goal: Goal<I, (I::Ty, I::Ty)>,
a_elem_ty: Ty<'tcx>, a_elem_ty: I::Ty,
b_elem_ty: Ty<'tcx>, b_elem_ty: I::Ty,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
self.eq(goal.param_env, a_elem_ty, b_elem_ty)?; self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc) self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) .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( fn consider_builtin_struct_unsize(
&mut self, &mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, goal: Goal<I, (I::Ty, I::Ty)>,
def: ty::AdtDef<'tcx>, def: I::AdtDef,
a_args: ty::GenericArgsRef<'tcx>, a_args: I::GenericArgs,
b_args: ty::GenericArgsRef<'tcx>, b_args: I::GenericArgs,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let tcx = self.interner(); let tcx = self.interner();
let Goal { predicate: (_a_ty, b_ty), .. } = goal; 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 // We must be unsizing some type parameters. This also implies
// that the struct has a tail field. // that the struct has a tail field.
if unsizing_params.is_empty() { if unsizing_params.is_empty() {
return Err(NoSolution); return Err(NoSolution);
} }
let tail_field = def.non_enum_variant().tail(); let tail_field_ty = def.struct_tail_ty(tcx).unwrap();
let tail_field_ty = tcx.type_of(tail_field.did);
let a_tail_ty = tail_field_ty.instantiate(tcx, a_args); let a_tail_ty = tail_field_ty.instantiate(tcx, &a_args);
let b_tail_ty = tail_field_ty.instantiate(tcx, b_args); let b_tail_ty = tail_field_ty.instantiate(tcx, &b_args);
// Instantiate just the unsizing params from B into A. The type after // 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 // 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 a_args
.iter() .iter()
.enumerate() .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); let unsized_a_ty = Ty::new_adt(tcx, def, new_a_args);
@ -986,7 +987,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
tcx, tcx,
ty::TraitRef::new( ty::TraitRef::new(
tcx, tcx,
tcx.require_lang_item(LangItem::Unsize, None), tcx.require_lang_item(TraitSolverLangItem::Unsize),
[a_tail_ty, b_tail_ty], [a_tail_ty, b_tail_ty],
), ),
), ),
@ -1007,10 +1008,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// ``` /// ```
fn consider_builtin_tuple_unsize( fn consider_builtin_tuple_unsize(
&mut self, &mut self,
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>, goal: Goal<I, (I::Ty, I::Ty)>,
a_tys: &'tcx ty::List<Ty<'tcx>>, a_tys: I::Tys,
b_tys: &'tcx ty::List<Ty<'tcx>>, b_tys: I::Tys,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
let tcx = self.interner(); let tcx = self.interner();
let Goal { predicate: (_a_ty, b_ty), .. } = goal; let Goal { predicate: (_a_ty, b_ty), .. } = goal;
@ -1029,7 +1030,7 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
tcx, tcx,
ty::TraitRef::new( ty::TraitRef::new(
tcx, tcx,
tcx.require_lang_item(LangItem::Unsize, None), tcx.require_lang_item(TraitSolverLangItem::Unsize),
[a_last_ty, b_last_ty], [a_last_ty, b_last_ty],
), ),
), ),
@ -1044,10 +1045,10 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
// the type's constituent types. // the type's constituent types.
fn disqualify_auto_trait_candidate_due_to_possible_impl( fn disqualify_auto_trait_candidate_due_to_possible_impl(
&mut self, &mut self,
goal: Goal<'tcx, TraitPredicate<'tcx>>, goal: Goal<I, TraitPredicate<I>>,
) -> Option<Result<Candidate<TyCtxt<'tcx>>, NoSolution>> { ) -> Option<Result<Candidate<I>, NoSolution>> {
let self_ty = goal.predicate.self_ty(); 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 // Stall int and float vars until they are resolved to a concrete
// numerical type. That's because the check for impls below treats // numerical type. That's because the check for impls below treats
// int vars as matching any impl. Even if we filtered such impls, // 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::Alias(ty::Projection | ty::Weak | ty::Inherent, ..)
| ty::Placeholder(..) => Some(Err(NoSolution)), | 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 // Coroutines have one special built-in candidate, `Unpin`, which
// takes precedence over the structural auto trait candidate being // takes precedence over the structural auto trait candidate being
// assembled. // assembled.
ty::Coroutine(def_id, _) 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) { match self.interner().coroutine_movability(def_id) {
Movability::Static => Some(Err(NoSolution)), Movability::Static => Some(Err(NoSolution)),
@ -1144,13 +1147,13 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
/// wrapped in one. /// wrapped in one.
fn probe_and_evaluate_goal_for_constituent_tys( fn probe_and_evaluate_goal_for_constituent_tys(
&mut self, &mut self,
source: CandidateSource<'tcx>, source: CandidateSource<I>,
goal: Goal<'tcx, TraitPredicate<'tcx>>, goal: Goal<I, TraitPredicate<I>>,
constituent_tys: impl Fn( constituent_tys: impl Fn(
&EvalCtxt<'_, SolverDelegate<'tcx>>, &EvalCtxt<'_, Infcx>,
Ty<'tcx>, I::Ty,
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>, ) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>,
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> { ) -> Result<Candidate<I>, NoSolution> {
self.probe_trait_candidate(source).enter(|ecx| { self.probe_trait_candidate(source).enter(|ecx| {
ecx.add_goals( ecx.add_goals(
GoalSource::ImplWhereBound, GoalSource::ImplWhereBound,
@ -1173,8 +1176,8 @@ impl<'tcx> EvalCtxt<'_, SolverDelegate<'tcx>> {
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
pub(super) fn compute_trait_goal( pub(super) fn compute_trait_goal(
&mut self, &mut self,
goal: Goal<'tcx, TraitPredicate<'tcx>>, goal: Goal<I, TraitPredicate<I>>,
) -> QueryResult<'tcx> { ) -> QueryResult<I> {
let candidates = self.assemble_and_evaluate_candidates(goal); let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_candidates(candidates) 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::fold::{TypeFoldable, TypeSuperFoldable};
use crate::relate::Relate; 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::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{self as ty, CollectAndApply, Interner, UpcastFrom}; use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
@ -29,10 +29,14 @@ pub trait Ty<I: Interner<Ty = Self>>:
+ Relate<I> + Relate<I>
+ Flags + Flags
{ {
fn new_unit(interner: I) -> Self;
fn new_bool(interner: I) -> Self; fn new_bool(interner: I) -> Self;
fn new_u8(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_infer(interner: I, var: ty::InferTy) -> Self;
fn new_var(interner: I, var: ty::TyVid) -> 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(_))) 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>> { fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
match self.kind() { match self.kind() {
ty::FnPtr(sig) => sig, 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), _ => 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>>: 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_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 { fn is_ct_var(self) -> bool {
matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_))) 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::Region>
+ From<I::Const> + 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>>: 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 } 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") 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(), 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>>: pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
@ -262,8 +363,17 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
+ Default + Default
+ Relate<I> + 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 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 identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs;
fn extend_with_error( fn extend_with_error(
@ -303,6 +413,9 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
+ UpcastFrom<I, ty::NormalizesTo<I>> + UpcastFrom<I, ty::NormalizesTo<I>>
+ UpcastFrom<I, ty::TraitRef<I>> + UpcastFrom<I, ty::TraitRef<I>>
+ UpcastFrom<I, ty::Binder<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>>> + IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
{ {
fn is_coinductive(self, interner: I) -> bool; fn is_coinductive(self, interner: I) -> bool;
@ -318,9 +431,34 @@ pub trait Clause<I: Interner<Clause = Self>>:
+ Eq + Eq
+ TypeFoldable<I> + TypeFoldable<I>
// FIXME: Remove these, uplift the `Upcast` impls. // FIXME: Remove these, uplift the `Upcast` impls.
+ UpcastFrom<I, ty::TraitRef<I>>
+ UpcastFrom<I, ty::Binder<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>>> + 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 /// Common capabilities of placeholder kinds
@ -352,18 +490,33 @@ pub trait ParamLike {
pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq { pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
fn def_id(self) -> I::DefId; 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; fn is_phantom_data(self) -> bool;
// FIXME: perhaps use `all_fields` and expose `FieldDef`. // 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>>; 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 { pub trait Features<I: Interner>: Copy {
fn generic_const_exprs(self) -> bool; fn generic_const_exprs(self) -> bool;
fn coroutine_clone(self) -> bool; fn coroutine_clone(self) -> bool;
fn associated_const_equality(self) -> bool;
} }
pub trait EvaluationCache<I: Interner> { pub trait EvaluationCache<I: Interner> {
@ -392,3 +545,26 @@ pub trait EvaluationCache<I: Interner> {
available_depth: usize, available_depth: usize,
) -> Option<CacheData<I>>; ) -> 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_ast_ir::Movability;
use rustc_index::bit_set::BitSet;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
@ -10,7 +11,7 @@ use crate::ir_print::IrPrint;
use crate::lang_items::TraitSolverLangItem; use crate::lang_items::TraitSolverLangItem;
use crate::relate::Relate; use crate::relate::Relate;
use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::solve::inspect::CanonicalGoalEvaluationStep;
use crate::solve::{ExternalConstraintsData, SolverMode}; use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode};
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
use crate::{self as ty}; use crate::{self as ty};
@ -29,9 +30,8 @@ pub trait Interner:
+ IrPrint<ty::CoercePredicate<Self>> + IrPrint<ty::CoercePredicate<Self>>
+ IrPrint<ty::FnSig<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 LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
type AdtDef: AdtDef<Self>;
type GenericArgs: GenericArgs<Self>; type GenericArgs: GenericArgs<Self>;
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
@ -46,18 +46,45 @@ pub trait Interner:
+ Default; + Default;
type BoundVarKind: Copy + Debug + Hash + Eq; type BoundVarKind: Copy + Debug + Hash + Eq;
type PredefinedOpaques: Copy + Debug + Hash + Eq; type PredefinedOpaques: Copy
type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>; + 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 type CanonicalGoalEvaluationStepRef: Copy
+ Debug + Debug
+ Hash + Hash
+ Eq + Eq
+ Deref<Target = CanonicalGoalEvaluationStep<Self>>; + 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; 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( fn mk_external_constraints(
self, self,
data: ExternalConstraintsData<Self>, data: ExternalConstraintsData<Self>,
@ -76,12 +103,7 @@ pub trait Interner:
// Things stored inside of tys // Things stored inside of tys
type ErrorGuaranteed: Copy + Debug + Hash + Eq; type ErrorGuaranteed: Copy + Debug + Hash + Eq;
type BoundExistentialPredicates: Copy type BoundExistentialPredicates: BoundExistentialPredicates<Self>;
+ Debug
+ Hash
+ Eq
+ Relate<Self>
+ IntoIterator<Item = ty::Binder<Self, ty::ExistentialPredicate<Self>>>;
type AllocId: Copy + Debug + Hash + Eq; type AllocId: Copy + Debug + Hash + Eq;
type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>; type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
type Safety: Safety<Self>; type Safety: Safety<Self>;
@ -103,7 +125,7 @@ pub trait Interner:
type PlaceholderRegion: PlaceholderLike; type PlaceholderRegion: PlaceholderLike;
// Predicates // Predicates
type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable<Self>; type ParamEnv: ParamEnv<Self>;
type Predicate: Predicate<Self>; type Predicate: Predicate<Self>;
type Clause: Clause<Self>; type Clause: Clause<Self>;
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
@ -123,9 +145,11 @@ pub trait Interner:
+ IntoIterator<Item: Deref<Target = ty::Variance>>; + IntoIterator<Item: Deref<Target = ty::Variance>>;
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; 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>; 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_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind;
fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind; fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind;
@ -143,6 +167,8 @@ pub trait Interner:
I: Iterator<Item = T>, I: Iterator<Item = T>,
T: CollectAndApply<Self::GenericArg, Self::GenericArgs>; T: CollectAndApply<Self::GenericArg, Self::GenericArgs>;
fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool;
fn check_and_mk_args( fn check_and_mk_args(
self, self,
def_id: Self::DefId, def_id: Self::DefId,
@ -187,6 +213,17 @@ pub trait Interner:
def_id: Self::DefId, def_id: Self::DefId,
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>; ) -> 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( fn super_predicates_of(
self, self,
def_id: Self::DefId, def_id: Self::DefId,
@ -196,7 +233,64 @@ pub trait Interner:
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; 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>; 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` /// 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 /// 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. /// representation of `LangItem`s used in the underlying compiler implementation.
pub enum TraitSolverLangItem { pub enum TraitSolverLangItem {
Future, // tidy-alphabetical-start
FutureOutput, AsyncDestruct,
AsyncFnKindHelper, AsyncFnKindHelper,
AsyncFnKindUpvars, 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::inherent::*;
use crate::lift::Lift; use crate::lift::Lift;
use crate::upcast::Upcast; use crate::upcast::{Upcast, UpcastFrom};
use crate::visit::TypeVisitableExt as _; use crate::visit::TypeVisitableExt as _;
use crate::{self as ty, Interner}; 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> { impl<I: Interner> fmt::Debug for TraitPredicate<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// FIXME(effects) printing? // FIXME(effects) printing?