mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #126614 - compiler-errors:uplift-next-trait-solver, r=lcnr
Uplift next trait solver to `rustc_next_trait_solver`
🎉
There's so many FIXMEs! Sorry! Ideally this merges with the FIXMEs and we track and squash them over the near future.
Also, this still doesn't build on anything other than rustc. I still need to fix `feature = "nightly"` in `rustc_type_ir`, and remove and fix all the nightly feature usage in the new trait solver (notably: let-chains).
Also, sorry `@lcnr` I know you asked for me to separate the commit where we `mv rustc_trait_selection/solve/... rustc_next_trait_solver/solve/...`, but I had already done all the work by that point. Luckily, `git` understands the file moves so it should still be relatively reviewable.
If this is still very difficult to review, then I can do some rebasing magic to try to separate this out. Please let me know!
r? lcnr
This commit is contained in:
commit
8fcd4dd08e
@ -4520,7 +4520,16 @@ dependencies = [
|
||||
name = "rustc_next_trait_solver"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"derivative",
|
||||
"rustc_ast_ir",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"rustc_type_ir",
|
||||
"rustc_type_ir_macros",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -11,7 +11,7 @@ pub use BoundRegionConversionTime::*;
|
||||
pub use RegionVariableOrigin::*;
|
||||
pub use SubregionOrigin::*;
|
||||
|
||||
use crate::infer::relate::{Relate, RelateResult};
|
||||
use crate::infer::relate::RelateResult;
|
||||
use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine};
|
||||
use error_reporting::TypeErrCtxt;
|
||||
use free_regions::RegionRelations;
|
||||
@ -45,7 +45,7 @@ use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_span::Span;
|
||||
use snapshot::undo_log::InferCtxtUndoLogs;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::fmt;
|
||||
@ -335,149 +335,6 @@ pub struct InferCtxt<'tcx> {
|
||||
pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
|
||||
type Interner = TyCtxt<'tcx>;
|
||||
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn universe_of_ty(&self, vid: TyVid) -> Option<ty::UniverseIndex> {
|
||||
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
|
||||
// ty infers will give you the universe of the var it resolved to not the universe
|
||||
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
|
||||
// try to print out `?0.1` it will just print `?0`.
|
||||
match self.probe_ty_var(vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, ct: ConstVid) -> Option<ty::UniverseIndex> {
|
||||
// Same issue as with `universe_of_ty`
|
||||
match self.probe_const_var(ct) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn root_ty_var(&self, var: TyVid) -> TyVid {
|
||||
self.root_var(var)
|
||||
}
|
||||
|
||||
fn root_const_var(&self, var: ConstVid) -> ConstVid {
|
||||
self.root_const_var(var)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
|
||||
match self.probe_ty_var(vid) {
|
||||
Ok(ty) => ty,
|
||||
Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> {
|
||||
self.opportunistic_resolve_int_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> {
|
||||
self.opportunistic_resolve_float_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ty::Const<'tcx> {
|
||||
match self.probe_const_var(vid) {
|
||||
Ok(ct) => ct,
|
||||
Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> ty::Const<'tcx> {
|
||||
match self.probe_effect_var(vid) {
|
||||
Some(ct) => ct,
|
||||
None => {
|
||||
ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types
|
||||
}
|
||||
|
||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||
self.next_ty_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn next_const_infer(&self) -> ty::Const<'tcx> {
|
||||
self.next_const_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
self.fresh_args_for_item(DUMMY_SP, def_id)
|
||||
}
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T {
|
||||
self.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.enter_forall(value, f)
|
||||
}
|
||||
|
||||
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
|
||||
}
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.at(&ObligationCause::dummy(), param_env)
|
||||
.eq_structurally_relating_aliases_no_trace(lhs, rhs)
|
||||
}
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.resolve_vars_if_possible(value)
|
||||
}
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
|
||||
self.probe(|_| probe())
|
||||
}
|
||||
}
|
||||
|
||||
/// See the `error_reporting` module for more details.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
|
||||
pub enum ValuePairs<'tcx> {
|
||||
@ -831,6 +688,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
self.tcx.dcx()
|
||||
}
|
||||
|
||||
pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.defining_opaque_types
|
||||
}
|
||||
|
||||
pub fn next_trait_solver(&self) -> bool {
|
||||
self.next_trait_solver
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ macro_rules! arena_types {
|
||||
rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>>
|
||||
>,
|
||||
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<rustc_middle::ty::TyCtxt<'tcx>>,
|
||||
[] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>,
|
||||
[] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<rustc_middle::ty::TyCtxt<'tcx>>,
|
||||
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
|
||||
[] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem,
|
||||
[] mod_child: rustc_middle::metadata::ModChild,
|
||||
|
@ -5,12 +5,12 @@ use rustc_type_ir as ir;
|
||||
pub use rustc_type_ir::solve::*;
|
||||
|
||||
use crate::ty::{
|
||||
self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
|
||||
self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
|
||||
};
|
||||
|
||||
mod cache;
|
||||
|
||||
pub use cache::{CacheData, EvaluationCache};
|
||||
pub use cache::EvaluationCache;
|
||||
|
||||
pub type Goal<'tcx, P> = ir::solve::Goal<TyCtxt<'tcx>, P>;
|
||||
pub type QueryInput<'tcx, P> = ir::solve::QueryInput<TyCtxt<'tcx>, P>;
|
||||
@ -19,17 +19,11 @@ pub type CandidateSource<'tcx> = ir::solve::CandidateSource<TyCtxt<'tcx>>;
|
||||
pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput<TyCtxt<'tcx>, P>;
|
||||
pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse<TyCtxt<'tcx>>;
|
||||
|
||||
/// Additional constraints returned on success.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
|
||||
pub struct PredefinedOpaquesData<'tcx> {
|
||||
pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)]
|
||||
pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>);
|
||||
pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>);
|
||||
|
||||
impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> {
|
||||
type Target = PredefinedOpaquesData<'tcx>;
|
||||
type Target = PredefinedOpaquesData<TyCtxt<'tcx>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
|
@ -5,6 +5,8 @@ use rustc_data_structures::sync::Lock;
|
||||
use rustc_query_system::cache::WithDepNode;
|
||||
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||
use rustc_session::Limit;
|
||||
use rustc_type_ir::solve::CacheData;
|
||||
|
||||
/// The trait solver cache used by `-Znext-solver`.
|
||||
///
|
||||
/// FIXME(@lcnr): link to some official documentation of how
|
||||
@ -14,17 +16,9 @@ pub struct EvaluationCache<'tcx> {
|
||||
map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct CacheData<'tcx> {
|
||||
pub result: QueryResult<'tcx>,
|
||||
pub proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>>,
|
||||
pub additional_depth: usize,
|
||||
pub encountered_overflow: bool,
|
||||
}
|
||||
|
||||
impl<'tcx> EvaluationCache<'tcx> {
|
||||
impl<'tcx> rustc_type_ir::inherent::EvaluationCache<TyCtxt<'tcx>> for &'tcx EvaluationCache<'tcx> {
|
||||
/// Insert a final result into the global cache.
|
||||
pub fn insert(
|
||||
fn insert(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: CanonicalInput<'tcx>,
|
||||
@ -48,7 +42,7 @@ impl<'tcx> EvaluationCache<'tcx> {
|
||||
if cfg!(debug_assertions) {
|
||||
drop(map);
|
||||
let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow };
|
||||
let actual = self.get(tcx, key, [], Limit(additional_depth));
|
||||
let actual = self.get(tcx, key, [], additional_depth);
|
||||
if !actual.as_ref().is_some_and(|actual| expected == *actual) {
|
||||
bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}");
|
||||
}
|
||||
@ -59,13 +53,13 @@ impl<'tcx> EvaluationCache<'tcx> {
|
||||
/// and handling root goals of coinductive cycles.
|
||||
///
|
||||
/// If this returns `Some` the cache result can be used.
|
||||
pub fn get(
|
||||
fn get(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
key: CanonicalInput<'tcx>,
|
||||
stack_entries: impl IntoIterator<Item = CanonicalInput<'tcx>>,
|
||||
available_depth: Limit,
|
||||
) -> Option<CacheData<'tcx>> {
|
||||
available_depth: usize,
|
||||
) -> Option<CacheData<TyCtxt<'tcx>>> {
|
||||
let map = self.map.borrow();
|
||||
let entry = map.get(&key)?;
|
||||
|
||||
@ -76,7 +70,7 @@ impl<'tcx> EvaluationCache<'tcx> {
|
||||
}
|
||||
|
||||
if let Some(ref success) = entry.success {
|
||||
if available_depth.value_within_limit(success.additional_depth) {
|
||||
if Limit(available_depth).value_within_limit(success.additional_depth) {
|
||||
let QueryData { result, proof_tree } = success.data.get(tcx);
|
||||
return Some(CacheData {
|
||||
result,
|
||||
@ -87,12 +81,12 @@ impl<'tcx> EvaluationCache<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
entry.with_overflow.get(&available_depth.0).map(|e| {
|
||||
entry.with_overflow.get(&available_depth).map(|e| {
|
||||
let QueryData { result, proof_tree } = e.get(tcx);
|
||||
CacheData {
|
||||
result,
|
||||
proof_tree,
|
||||
additional_depth: available_depth.0,
|
||||
additional_depth: available_depth,
|
||||
encountered_overflow: true,
|
||||
}
|
||||
})
|
||||
|
@ -205,6 +205,14 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
|
||||
self.did()
|
||||
}
|
||||
|
||||
fn is_struct(self) -> bool {
|
||||
self.is_struct()
|
||||
}
|
||||
|
||||
fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
|
||||
Some(interner.type_of(self.non_enum_variant().tail_opt()?.did))
|
||||
}
|
||||
|
||||
fn is_phantom_data(self) -> bool {
|
||||
self.is_phantom_data()
|
||||
}
|
||||
@ -212,7 +220,7 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
|
||||
fn all_field_tys(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> ty::EarlyBinder<'tcx, impl Iterator<Item = Ty<'tcx>>> {
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = Ty<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()),
|
||||
)
|
||||
|
@ -16,8 +16,8 @@ mod valtree;
|
||||
|
||||
pub use int::*;
|
||||
pub use kind::*;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
pub use valtree::*;
|
||||
|
||||
pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
|
||||
@ -176,6 +176,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
|
||||
fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self {
|
||||
Const::new_expr(interner, expr)
|
||||
}
|
||||
|
||||
fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self {
|
||||
Const::new_error(interner, guar)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Const<'tcx> {
|
||||
|
@ -73,6 +73,7 @@ use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::solve::SolverMode;
|
||||
use rustc_type_ir::TyKind::*;
|
||||
use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo};
|
||||
use tracing::{debug, instrument};
|
||||
@ -91,46 +92,65 @@ use std::ops::{Bound, Deref};
|
||||
impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
type DefId = DefId;
|
||||
type LocalDefId = LocalDefId;
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
|
||||
type GenericArgs = ty::GenericArgsRef<'tcx>;
|
||||
|
||||
type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>];
|
||||
type GenericArg = ty::GenericArg<'tcx>;
|
||||
type Term = ty::Term<'tcx>;
|
||||
|
||||
type BoundVarKinds = &'tcx List<ty::BoundVariableKind>;
|
||||
type BoundVarKind = ty::BoundVariableKind;
|
||||
|
||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||
type BoundVarKind = ty::BoundVariableKind;
|
||||
type PredefinedOpaques = solve::PredefinedOpaques<'tcx>;
|
||||
|
||||
fn mk_predefined_opaques_in_body(
|
||||
self,
|
||||
data: PredefinedOpaquesData<Self>,
|
||||
) -> Self::PredefinedOpaques {
|
||||
self.mk_predefined_opaques_in_body(data)
|
||||
}
|
||||
type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
|
||||
type ExternalConstraints = ExternalConstraints<'tcx>;
|
||||
type CanonicalGoalEvaluationStepRef =
|
||||
&'tcx solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>;
|
||||
type CanonicalVars = CanonicalVarInfos<'tcx>;
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
|
||||
self.mk_canonical_var_infos(infos)
|
||||
}
|
||||
|
||||
type ExternalConstraints = ExternalConstraints<'tcx>;
|
||||
fn mk_external_constraints(
|
||||
self,
|
||||
data: ExternalConstraintsData<Self>,
|
||||
) -> ExternalConstraints<'tcx> {
|
||||
self.mk_external_constraints(data)
|
||||
}
|
||||
type DepNodeIndex = DepNodeIndex;
|
||||
fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) {
|
||||
self.dep_graph.with_anon_task(self, crate::dep_graph::dep_kinds::TraitSelect, task)
|
||||
}
|
||||
type Ty = Ty<'tcx>;
|
||||
type Tys = &'tcx List<Ty<'tcx>>;
|
||||
|
||||
type FnInputTys = &'tcx [Ty<'tcx>];
|
||||
type ParamTy = ParamTy;
|
||||
type BoundTy = ty::BoundTy;
|
||||
type PlaceholderTy = ty::PlaceholderType;
|
||||
|
||||
type PlaceholderTy = ty::PlaceholderType;
|
||||
type ErrorGuaranteed = ErrorGuaranteed;
|
||||
type BoundExistentialPredicates = &'tcx List<PolyExistentialPredicate<'tcx>>;
|
||||
type AllocId = crate::mir::interpret::AllocId;
|
||||
|
||||
type AllocId = crate::mir::interpret::AllocId;
|
||||
type Pat = Pattern<'tcx>;
|
||||
type Safety = hir::Safety;
|
||||
type Abi = abi::Abi;
|
||||
|
||||
type Const = ty::Const<'tcx>;
|
||||
type PlaceholderConst = ty::PlaceholderConst;
|
||||
|
||||
type ParamConst = ty::ParamConst;
|
||||
type BoundConst = ty::BoundVar;
|
||||
type ValueConst = ty::ValTree<'tcx>;
|
||||
type ExprConst = ty::Expr<'tcx>;
|
||||
|
||||
type Region = Region<'tcx>;
|
||||
|
||||
type EarlyParamRegion = ty::EarlyParamRegion;
|
||||
type LateParamRegion = ty::LateParamRegion;
|
||||
type BoundRegion = ty::BoundRegion;
|
||||
@ -138,15 +158,21 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
|
||||
type ParamEnv = ty::ParamEnv<'tcx>;
|
||||
type Predicate = Predicate<'tcx>;
|
||||
|
||||
type Clause = Clause<'tcx>;
|
||||
type Clauses = ty::Clauses<'tcx>;
|
||||
|
||||
fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
|
||||
self.expand_abstract_consts(t)
|
||||
type EvaluationCache = &'tcx solve::EvaluationCache<'tcx>;
|
||||
|
||||
fn evaluation_cache(self, mode: SolverMode) -> &'tcx solve::EvaluationCache<'tcx> {
|
||||
match mode {
|
||||
SolverMode::Normal => &self.new_solver_evaluation_cache,
|
||||
SolverMode::Coherence => &self.new_solver_coherence_evaluation_cache,
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
|
||||
self.mk_canonical_var_infos(infos)
|
||||
fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T {
|
||||
self.expand_abstract_consts(t)
|
||||
}
|
||||
|
||||
type GenericsOf = &'tcx ty::Generics;
|
||||
@ -165,6 +191,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
self.type_of(def_id)
|
||||
}
|
||||
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
fn adt_def(self, adt_def_id: DefId) -> Self::AdtDef {
|
||||
self.adt_def(adt_def_id)
|
||||
}
|
||||
|
||||
fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
|
||||
match self.def_kind(alias.def_id) {
|
||||
DefKind::AssocTy => {
|
||||
@ -202,8 +233,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
fn trait_ref_and_own_args_for_alias(
|
||||
self,
|
||||
def_id: DefId,
|
||||
args: Self::GenericArgs,
|
||||
) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) {
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
|
||||
assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
|
||||
let trait_def_id = self.parent(def_id);
|
||||
assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
|
||||
@ -214,18 +245,22 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs {
|
||||
fn mk_args(self, args: &[Self::GenericArg]) -> ty::GenericArgsRef<'tcx> {
|
||||
self.mk_args(args)
|
||||
}
|
||||
|
||||
fn mk_args_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::GenericArg, Self::GenericArgs>,
|
||||
T: CollectAndApply<Self::GenericArg, ty::GenericArgsRef<'tcx>>,
|
||||
{
|
||||
self.mk_args_from_iter(args)
|
||||
}
|
||||
|
||||
fn check_args_compatible(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> bool {
|
||||
self.check_args_compatible(def_id, args)
|
||||
}
|
||||
|
||||
fn check_and_mk_args(
|
||||
self,
|
||||
def_id: DefId,
|
||||
@ -244,7 +279,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::Ty, Self::Tys>,
|
||||
T: CollectAndApply<Ty<'tcx>, &'tcx List<Ty<'tcx>>>,
|
||||
{
|
||||
self.mk_type_list_from_iter(args)
|
||||
}
|
||||
@ -293,6 +328,24 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
self.item_bounds(def_id).map_bound(IntoIterator::into_iter)
|
||||
}
|
||||
|
||||
fn predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.predicates_of(def_id).instantiate_identity(self).predicates.into_iter(),
|
||||
)
|
||||
}
|
||||
|
||||
fn own_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
|
||||
ty::EarlyBinder::bind(
|
||||
self.predicates_of(def_id).instantiate_own_identity().map(|(clause, _)| clause),
|
||||
)
|
||||
}
|
||||
|
||||
fn super_predicates_of(
|
||||
self,
|
||||
def_id: DefId,
|
||||
@ -307,15 +360,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
}
|
||||
|
||||
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId {
|
||||
self.require_lang_item(
|
||||
match lang_item {
|
||||
TraitSolverLangItem::Future => hir::LangItem::Future,
|
||||
TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput,
|
||||
TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper,
|
||||
TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars,
|
||||
},
|
||||
None,
|
||||
)
|
||||
self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None)
|
||||
}
|
||||
|
||||
fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool {
|
||||
self.is_lang_item(def_id, trait_lang_item_to_lang_item(lang_item))
|
||||
}
|
||||
|
||||
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||
@ -324,6 +373,257 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
.filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
|
||||
.map(|assoc_item| assoc_item.def_id)
|
||||
}
|
||||
|
||||
fn args_may_unify_deep(
|
||||
self,
|
||||
obligation_args: ty::GenericArgsRef<'tcx>,
|
||||
impl_args: ty::GenericArgsRef<'tcx>,
|
||||
) -> bool {
|
||||
ty::fast_reject::DeepRejectCtxt {
|
||||
treat_obligation_params: ty::fast_reject::TreatParams::ForLookup,
|
||||
}
|
||||
.args_may_unify(obligation_args, impl_args)
|
||||
}
|
||||
|
||||
// This implementation is a bit different from `TyCtxt::for_each_relevant_impl`,
|
||||
// since we want to skip over blanket impls for non-rigid aliases, and also we
|
||||
// only want to consider types that *actually* unify with float/int vars.
|
||||
fn for_each_relevant_impl(
|
||||
self,
|
||||
trait_def_id: DefId,
|
||||
self_ty: Ty<'tcx>,
|
||||
mut f: impl FnMut(DefId),
|
||||
) {
|
||||
let tcx = self;
|
||||
let trait_impls = tcx.trait_impls_of(trait_def_id);
|
||||
let mut consider_impls_for_simplified_type = |simp| {
|
||||
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
|
||||
for &impl_def_id in impls_for_type {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::Never
|
||||
| ty::Tuple(_) => {
|
||||
let simp = ty::fast_reject::simplify_type(
|
||||
tcx,
|
||||
self_ty,
|
||||
ty::fast_reject::TreatParams::ForLookup,
|
||||
)
|
||||
.unwrap();
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
|
||||
// HACK: For integer and float variables we have to manually look at all impls
|
||||
// which have some integer or float as a self type.
|
||||
ty::Infer(ty::IntVar(_)) => {
|
||||
use ty::IntTy::*;
|
||||
use ty::UintTy::*;
|
||||
// This causes a compiler error if any new integer kinds are added.
|
||||
let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
|
||||
let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
|
||||
let possible_integers = [
|
||||
// signed integers
|
||||
ty::SimplifiedType::Int(I8),
|
||||
ty::SimplifiedType::Int(I16),
|
||||
ty::SimplifiedType::Int(I32),
|
||||
ty::SimplifiedType::Int(I64),
|
||||
ty::SimplifiedType::Int(I128),
|
||||
ty::SimplifiedType::Int(Isize),
|
||||
// unsigned integers
|
||||
ty::SimplifiedType::Uint(U8),
|
||||
ty::SimplifiedType::Uint(U16),
|
||||
ty::SimplifiedType::Uint(U32),
|
||||
ty::SimplifiedType::Uint(U64),
|
||||
ty::SimplifiedType::Uint(U128),
|
||||
ty::SimplifiedType::Uint(Usize),
|
||||
];
|
||||
for simp in possible_integers {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
ty::Infer(ty::FloatVar(_)) => {
|
||||
// This causes a compiler error if any new float kinds are added.
|
||||
let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128);
|
||||
let possible_floats = [
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F16),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F32),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F64),
|
||||
ty::SimplifiedType::Float(ty::FloatTy::F128),
|
||||
];
|
||||
|
||||
for simp in possible_floats {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
// The only traits applying to aliases and placeholders are blanket impls.
|
||||
//
|
||||
// Impls which apply to an alias after normalization are handled by
|
||||
// `assemble_candidates_after_normalizing_self_ty`.
|
||||
ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
|
||||
|
||||
// FIXME: These should ideally not exist as a self type. It would be nice for
|
||||
// the builtin auto trait impls of coroutines to instead directly recurse
|
||||
// into the witness.
|
||||
ty::CoroutineWitness(..) => (),
|
||||
|
||||
// These variants should not exist as a self type.
|
||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
|
||||
}
|
||||
|
||||
let trait_impls = tcx.trait_impls_of(trait_def_id);
|
||||
for &impl_def_id in trait_impls.blanket_impls() {
|
||||
f(impl_def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn has_item_definition(self, def_id: DefId) -> bool {
|
||||
self.defaultness(def_id).has_value()
|
||||
}
|
||||
|
||||
fn impl_is_default(self, impl_def_id: DefId) -> bool {
|
||||
self.defaultness(impl_def_id).is_default()
|
||||
}
|
||||
|
||||
fn impl_trait_ref(self, impl_def_id: DefId) -> ty::EarlyBinder<'tcx, ty::TraitRef<'tcx>> {
|
||||
self.impl_trait_ref(impl_def_id).unwrap()
|
||||
}
|
||||
|
||||
fn impl_polarity(self, impl_def_id: DefId) -> ty::ImplPolarity {
|
||||
self.impl_polarity(impl_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_auto(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_auto(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_alias(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_alias(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_is_object_safe(self, trait_def_id: DefId) -> bool {
|
||||
self.is_object_safe(trait_def_id)
|
||||
}
|
||||
|
||||
fn trait_may_be_implemented_via_object(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_def(trait_def_id).implement_via_object
|
||||
}
|
||||
|
||||
fn fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option<ty::ClosureKind> {
|
||||
self.fn_trait_kind_from_def_id(trait_def_id)
|
||||
}
|
||||
|
||||
fn async_fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option<ty::ClosureKind> {
|
||||
self.async_fn_trait_kind_from_def_id(trait_def_id)
|
||||
}
|
||||
|
||||
fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator<Item = DefId> {
|
||||
self.supertrait_def_ids(trait_def_id)
|
||||
}
|
||||
|
||||
fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed {
|
||||
self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string())
|
||||
}
|
||||
|
||||
fn is_general_coroutine(self, coroutine_def_id: DefId) -> bool {
|
||||
self.is_general_coroutine(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_async(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_async(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_gen(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_gen(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn coroutine_is_async_gen(self, coroutine_def_id: DefId) -> bool {
|
||||
self.coroutine_is_async_gen(coroutine_def_id)
|
||||
}
|
||||
|
||||
fn layout_is_pointer_like(self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
self.layout_of(self.erase_regions(param_env.and(ty)))
|
||||
.is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout))
|
||||
}
|
||||
|
||||
type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>;
|
||||
fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
|
||||
self.unsizing_params_for_adt(adt_def_id)
|
||||
}
|
||||
|
||||
fn find_const_ty_from_env(
|
||||
self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
placeholder: Self::PlaceholderConst,
|
||||
) -> Ty<'tcx> {
|
||||
placeholder.find_const_ty_from_env(param_env)
|
||||
}
|
||||
}
|
||||
|
||||
fn trait_lang_item_to_lang_item(lang_item: TraitSolverLangItem) -> LangItem {
|
||||
match lang_item {
|
||||
TraitSolverLangItem::AsyncDestruct => LangItem::AsyncDestruct,
|
||||
TraitSolverLangItem::AsyncFnKindHelper => LangItem::AsyncFnKindHelper,
|
||||
TraitSolverLangItem::AsyncFnKindUpvars => LangItem::AsyncFnKindUpvars,
|
||||
TraitSolverLangItem::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput,
|
||||
TraitSolverLangItem::AsyncIterator => LangItem::AsyncIterator,
|
||||
TraitSolverLangItem::CallOnceFuture => LangItem::CallOnceFuture,
|
||||
TraitSolverLangItem::CallRefFuture => LangItem::CallRefFuture,
|
||||
TraitSolverLangItem::Clone => LangItem::Clone,
|
||||
TraitSolverLangItem::Copy => LangItem::Copy,
|
||||
TraitSolverLangItem::Coroutine => LangItem::Coroutine,
|
||||
TraitSolverLangItem::CoroutineReturn => LangItem::CoroutineReturn,
|
||||
TraitSolverLangItem::CoroutineYield => LangItem::CoroutineYield,
|
||||
TraitSolverLangItem::Destruct => LangItem::Destruct,
|
||||
TraitSolverLangItem::DiscriminantKind => LangItem::DiscriminantKind,
|
||||
TraitSolverLangItem::DynMetadata => LangItem::DynMetadata,
|
||||
TraitSolverLangItem::FnPtrTrait => LangItem::FnPtrTrait,
|
||||
TraitSolverLangItem::FusedIterator => LangItem::FusedIterator,
|
||||
TraitSolverLangItem::Future => LangItem::Future,
|
||||
TraitSolverLangItem::FutureOutput => LangItem::FutureOutput,
|
||||
TraitSolverLangItem::Iterator => LangItem::Iterator,
|
||||
TraitSolverLangItem::Metadata => LangItem::Metadata,
|
||||
TraitSolverLangItem::Option => LangItem::Option,
|
||||
TraitSolverLangItem::PointeeTrait => LangItem::PointeeTrait,
|
||||
TraitSolverLangItem::PointerLike => LangItem::PointerLike,
|
||||
TraitSolverLangItem::Poll => LangItem::Poll,
|
||||
TraitSolverLangItem::Sized => LangItem::Sized,
|
||||
TraitSolverLangItem::TransmuteTrait => LangItem::TransmuteTrait,
|
||||
TraitSolverLangItem::Tuple => LangItem::Tuple,
|
||||
TraitSolverLangItem::Unpin => LangItem::Unpin,
|
||||
TraitSolverLangItem::Unsize => LangItem::Unsize,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::DefId<TyCtxt<'tcx>> for DefId {
|
||||
fn as_local(self) -> Option<LocalDefId> {
|
||||
self.as_local()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
|
||||
@ -358,6 +658,10 @@ impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_featu
|
||||
fn coroutine_clone(self) -> bool {
|
||||
self.coroutine_clone
|
||||
}
|
||||
|
||||
fn associated_const_equality(self) -> bool {
|
||||
self.associated_const_equality
|
||||
}
|
||||
}
|
||||
|
||||
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
|
||||
@ -386,7 +690,7 @@ pub struct CtxtInterners<'tcx> {
|
||||
layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
|
||||
adt_def: InternedSet<'tcx, AdtDefData>,
|
||||
external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
|
||||
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
|
||||
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>,
|
||||
fields: InternedSet<'tcx, List<FieldIdx>>,
|
||||
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
|
||||
captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>,
|
||||
@ -2098,7 +2402,7 @@ direct_interners! {
|
||||
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
|
||||
external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>):
|
||||
ExternalConstraints -> ExternalConstraints<'tcx>,
|
||||
predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>):
|
||||
predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<TyCtxt<'tcx>>):
|
||||
PredefinedOpaques -> PredefinedOpaques<'tcx>,
|
||||
}
|
||||
|
||||
|
@ -44,10 +44,27 @@ pub struct GenericArg<'tcx> {
|
||||
impl<'tcx> rustc_type_ir::inherent::GenericArg<TyCtxt<'tcx>> for GenericArg<'tcx> {}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
|
||||
fn rebase_onto(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
source_ancestor: DefId,
|
||||
target_args: GenericArgsRef<'tcx>,
|
||||
) -> GenericArgsRef<'tcx> {
|
||||
self.rebase_onto(tcx, source_ancestor, target_args)
|
||||
}
|
||||
|
||||
fn type_at(self, i: usize) -> Ty<'tcx> {
|
||||
self.type_at(i)
|
||||
}
|
||||
|
||||
fn region_at(self, i: usize) -> ty::Region<'tcx> {
|
||||
self.region_at(i)
|
||||
}
|
||||
|
||||
fn const_at(self, i: usize) -> ty::Const<'tcx> {
|
||||
self.const_at(i)
|
||||
}
|
||||
|
||||
fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
GenericArgs::identity_for_item(tcx, def_id)
|
||||
}
|
||||
@ -281,6 +298,7 @@ impl<'tcx> GenericArg<'tcx> {
|
||||
pub fn is_non_region_infer(self) -> bool {
|
||||
match self.unpack() {
|
||||
GenericArgKind::Lifetime(_) => false,
|
||||
// FIXME: This shouldn't return numerical/float.
|
||||
GenericArgKind::Type(ty) => ty.is_ty_or_numeric_infer(),
|
||||
GenericArgKind::Const(ct) => ct.is_ct_infer(),
|
||||
}
|
||||
|
@ -392,6 +392,10 @@ impl<'tcx> GenericPredicates<'tcx> {
|
||||
EarlyBinder::bind(self.predicates).iter_instantiated_copied(tcx, args)
|
||||
}
|
||||
|
||||
pub fn instantiate_own_identity(&self) -> impl Iterator<Item = (Clause<'tcx>, Span)> {
|
||||
EarlyBinder::bind(self.predicates).instantiate_identity_iter_copied()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, tcx))]
|
||||
fn instantiate_into(
|
||||
&self,
|
||||
|
@ -990,6 +990,16 @@ pub struct ParamEnv<'tcx> {
|
||||
packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>,
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::ParamEnv<TyCtxt<'tcx>> for ParamEnv<'tcx> {
|
||||
fn reveal(self) -> Reveal {
|
||||
self.reveal()
|
||||
}
|
||||
|
||||
fn caller_bounds(self) -> impl IntoIterator<Item = ty::Clause<'tcx>> {
|
||||
self.caller_bounds()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct ParamTag {
|
||||
reveal: traits::Reveal,
|
||||
|
@ -175,6 +175,14 @@ pub struct Clause<'tcx>(
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {}
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::IntoKind for Clause<'tcx> {
|
||||
type Kind = ty::Binder<'tcx, ClauseKind<'tcx>>;
|
||||
|
||||
fn kind(self) -> Self::Kind {
|
||||
self.kind()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clause<'tcx> {
|
||||
pub fn as_predicate(self) -> Predicate<'tcx> {
|
||||
Predicate(self.0)
|
||||
@ -251,6 +259,28 @@ impl<'tcx> ExistentialPredicate<'tcx> {
|
||||
|
||||
pub type PolyExistentialPredicate<'tcx> = ty::Binder<'tcx, ExistentialPredicate<'tcx>>;
|
||||
|
||||
impl<'tcx> rustc_type_ir::inherent::BoundExistentialPredicates<TyCtxt<'tcx>>
|
||||
for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>
|
||||
{
|
||||
fn principal_def_id(self) -> Option<DefId> {
|
||||
self.principal_def_id()
|
||||
}
|
||||
|
||||
fn principal(self) -> Option<ty::PolyExistentialTraitRef<'tcx>> {
|
||||
self.principal()
|
||||
}
|
||||
|
||||
fn auto_traits(self) -> impl IntoIterator<Item = DefId> {
|
||||
self.auto_traits()
|
||||
}
|
||||
|
||||
fn projection_bounds(
|
||||
self,
|
||||
) -> impl IntoIterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> {
|
||||
self.projection_bounds()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
|
||||
/// Returns the "principal `DefId`" of this set of existential predicates.
|
||||
///
|
||||
@ -481,12 +511,6 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Predicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for TraitPredicate<'tcx> {
|
||||
fn upcast_from(from: TraitRef<'tcx>, _tcx: TyCtxt<'tcx>) -> Self {
|
||||
TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Clause<'tcx> {
|
||||
fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
let p: Predicate<'tcx> = from.upcast(tcx);
|
||||
@ -543,6 +567,12 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyTraitPredicate<'tcx>> for Clause<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, RegionOutlivesPredicate<'tcx>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: RegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
ty::Binder::dummy(PredicateKind::Clause(ClauseKind::RegionOutlives(from))).upcast(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyRegionOutlivesPredicate<'tcx>> for Predicate<'tcx> {
|
||||
fn upcast_from(from: PolyRegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
|
||||
from.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).upcast(tcx)
|
||||
|
@ -930,6 +930,22 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
|
||||
fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self {
|
||||
Ty::new_pat(interner, ty, pat)
|
||||
}
|
||||
|
||||
fn new_unit(interner: TyCtxt<'tcx>) -> Self {
|
||||
interner.types.unit
|
||||
}
|
||||
|
||||
fn new_usize(interner: TyCtxt<'tcx>) -> Self {
|
||||
interner.types.usize
|
||||
}
|
||||
|
||||
fn discriminant_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
self.discriminant_ty(interner)
|
||||
}
|
||||
|
||||
fn async_destructor_ty(self, interner: TyCtxt<'tcx>) -> Ty<'tcx> {
|
||||
self.async_destructor_ty(interner)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type utilities
|
||||
|
@ -565,42 +565,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checks whether each generic argument is simply a unique generic placeholder.
|
||||
///
|
||||
/// This is used in the new solver, which canonicalizes params to placeholders
|
||||
/// for better caching.
|
||||
pub fn uses_unique_placeholders_ignoring_regions(
|
||||
self,
|
||||
args: GenericArgsRef<'tcx>,
|
||||
) -> Result<(), NotUniqueParam<'tcx>> {
|
||||
let mut seen = GrowableBitSet::default();
|
||||
for arg in args {
|
||||
match arg.unpack() {
|
||||
// Ignore regions, since we can't resolve those in a canonicalized
|
||||
// query in the trait solver.
|
||||
GenericArgKind::Lifetime(_) => {}
|
||||
GenericArgKind::Type(t) => match t.kind() {
|
||||
ty::Placeholder(p) => {
|
||||
if !seen.insert(p.bound.var) {
|
||||
return Err(NotUniqueParam::DuplicateParam(t.into()));
|
||||
}
|
||||
}
|
||||
_ => return Err(NotUniqueParam::NotParam(t.into())),
|
||||
},
|
||||
GenericArgKind::Const(c) => match c.kind() {
|
||||
ty::ConstKind::Placeholder(p) => {
|
||||
if !seen.insert(p.bound) {
|
||||
return Err(NotUniqueParam::DuplicateParam(c.into()));
|
||||
}
|
||||
}
|
||||
_ => return Err(NotUniqueParam::NotParam(c.into())),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns `true` if `def_id` refers to a closure, coroutine, or coroutine-closure
|
||||
/// (i.e. an async closure). These are all represented by `hir::Closure`, and all
|
||||
/// have the same `DefKind`.
|
||||
|
@ -5,9 +5,25 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
derivative = "2.2.0"
|
||||
rustc_ast_ir = { path = "../rustc_ast_ir" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
rustc_index = { path = "../rustc_index", default-features = false }
|
||||
rustc_macros = { path = "../rustc_macros", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
|
||||
rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
|
||||
tracing = "0.1"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[features]
|
||||
default = ["nightly"]
|
||||
nightly = ["rustc_type_ir/nightly"]
|
||||
nightly = [
|
||||
"rustc_ast_ir/nightly",
|
||||
"rustc_data_structures",
|
||||
"rustc_index/nightly",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"rustc_type_ir/nightly",
|
||||
]
|
||||
|
@ -4,10 +4,11 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use rustc_type_ir::{
|
||||
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike,
|
||||
Interner,
|
||||
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner,
|
||||
};
|
||||
|
||||
use crate::infcx::SolverDelegate;
|
||||
|
||||
/// Whether we're canonicalizing a query input or the query response.
|
||||
///
|
||||
/// When canonicalizing an input we're in the context of the caller
|
||||
@ -37,7 +38,7 @@ pub enum CanonicalizeMode {
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Canonicalizer<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
|
||||
pub struct Canonicalizer<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> {
|
||||
infcx: &'a Infcx,
|
||||
canonicalize_mode: CanonicalizeMode,
|
||||
|
||||
@ -46,7 +47,7 @@ pub struct Canonicalizer<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
|
||||
binder_index: ty::DebruijnIndex,
|
||||
}
|
||||
|
||||
impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infcx, I> {
|
||||
impl<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, Infcx, I> {
|
||||
pub fn canonicalize<T: TypeFoldable<I>>(
|
||||
infcx: &'a Infcx,
|
||||
canonicalize_mode: CanonicalizeMode,
|
||||
@ -210,7 +211,7 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc
|
||||
}
|
||||
}
|
||||
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||
impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I>
|
||||
for Canonicalizer<'_, Infcx, I>
|
||||
{
|
||||
fn interner(&self) -> I {
|
||||
|
205
compiler/rustc_next_trait_solver/src/infcx.rs
Normal file
205
compiler/rustc_next_trait_solver/src/infcx.rs
Normal file
@ -0,0 +1,205 @@
|
||||
use std::fmt::Debug;
|
||||
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode};
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
|
||||
pub trait SolverDelegate: Sized {
|
||||
type Interner: Interner;
|
||||
fn interner(&self) -> Self::Interner;
|
||||
|
||||
type Span: Copy;
|
||||
|
||||
fn solver_mode(&self) -> SolverMode;
|
||||
|
||||
fn build_with_canonical<V>(
|
||||
interner: Self::Interner,
|
||||
solver_mode: SolverMode,
|
||||
canonical: &ty::Canonical<Self::Interner, V>,
|
||||
) -> (Self, V, ty::CanonicalVarValues<Self::Interner>)
|
||||
where
|
||||
V: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex;
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex;
|
||||
|
||||
fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_float_var(
|
||||
&self,
|
||||
vid: ty::FloatVid,
|
||||
) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_ct_var(
|
||||
&self,
|
||||
vid: ty::ConstVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_effect_var(
|
||||
&self,
|
||||
vid: ty::EffectVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_lt_var(
|
||||
&self,
|
||||
vid: ty::RegionVid,
|
||||
) -> <Self::Interner as Interner>::Region;
|
||||
|
||||
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
|
||||
|
||||
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
||||
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
||||
fn fresh_args_for_item(
|
||||
&self,
|
||||
def_id: <Self::Interner as Interner>::DefId,
|
||||
) -> <Self::Interner as Interner>::GenericArgs;
|
||||
|
||||
fn fresh_var_for_kind_with_span(
|
||||
&self,
|
||||
arg: <Self::Interner as Interner>::GenericArg,
|
||||
span: Self::Span,
|
||||
) -> <Self::Interner as Interner>::GenericArg;
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
) -> T;
|
||||
|
||||
fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U;
|
||||
|
||||
fn relate<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
|
||||
|
||||
// FIXME: Uplift the leak check into this crate.
|
||||
fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>;
|
||||
|
||||
// FIXME: This is only here because elaboration lives in `rustc_infer`!
|
||||
fn elaborate_supertraits(
|
||||
interner: Self::Interner,
|
||||
trait_ref: ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>,
|
||||
) -> impl Iterator<Item = ty::Binder<Self::Interner, ty::TraitRef<Self::Interner>>>;
|
||||
|
||||
fn try_const_eval_resolve(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
unevaluated: ty::UnevaluatedConst<Self::Interner>,
|
||||
) -> Option<<Self::Interner as Interner>::Const>;
|
||||
|
||||
fn sub_regions(
|
||||
&self,
|
||||
sub: <Self::Interner as Interner>::Region,
|
||||
sup: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
|
||||
fn register_ty_outlives(
|
||||
&self,
|
||||
ty: <Self::Interner as Interner>::Ty,
|
||||
r: <Self::Interner as Interner>::Region,
|
||||
);
|
||||
|
||||
// FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`!
|
||||
fn well_formed_goals(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
arg: <Self::Interner as Interner>::GenericArg,
|
||||
) -> Option<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>>;
|
||||
|
||||
fn clone_opaque_types_for_query_response(
|
||||
&self,
|
||||
) -> Vec<(ty::OpaqueTypeKey<Self::Interner>, <Self::Interner as Interner>::Ty)>;
|
||||
|
||||
fn make_deduplicated_outlives_constraints(
|
||||
&self,
|
||||
) -> Vec<ty::OutlivesPredicate<Self::Interner, <Self::Interner as Interner>::GenericArg>>;
|
||||
|
||||
fn instantiate_canonical<V>(
|
||||
&self,
|
||||
canonical: ty::Canonical<Self::Interner, V>,
|
||||
values: ty::CanonicalVarValues<Self::Interner>,
|
||||
) -> V
|
||||
where
|
||||
V: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn instantiate_canonical_var_with_infer(
|
||||
&self,
|
||||
cv_info: ty::CanonicalVarInfo<Self::Interner>,
|
||||
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
|
||||
) -> <Self::Interner as Interner>::GenericArg;
|
||||
|
||||
// FIXME: Can we implement this in terms of `add` and `inject`?
|
||||
fn insert_hidden_type(
|
||||
&self,
|
||||
opaque_type_key: ty::OpaqueTypeKey<Self::Interner>,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
hidden_ty: <Self::Interner as Interner>::Ty,
|
||||
goals: &mut Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
|
||||
) -> Result<(), NoSolution>;
|
||||
|
||||
fn add_item_bounds_for_hidden_type(
|
||||
&self,
|
||||
def_id: <Self::Interner as Interner>::DefId,
|
||||
args: <Self::Interner as Interner>::GenericArgs,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
hidden_ty: <Self::Interner as Interner>::Ty,
|
||||
goals: &mut Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
|
||||
);
|
||||
|
||||
fn inject_new_hidden_type_unchecked(
|
||||
&self,
|
||||
key: ty::OpaqueTypeKey<Self::Interner>,
|
||||
hidden_ty: <Self::Interner as Interner>::Ty,
|
||||
);
|
||||
|
||||
fn reset_opaque_types(&self);
|
||||
|
||||
fn trait_ref_is_knowable<E: Debug>(
|
||||
&self,
|
||||
trait_ref: ty::TraitRef<Self::Interner>,
|
||||
lazily_normalize_ty: impl FnMut(
|
||||
<Self::Interner as Interner>::Ty,
|
||||
) -> Result<<Self::Interner as Interner>::Ty, E>,
|
||||
) -> Result<bool, E>;
|
||||
|
||||
fn fetch_eligible_assoc_item(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
goal_trait_ref: ty::TraitRef<Self::Interner>,
|
||||
trait_assoc_def_id: <Self::Interner as Interner>::DefId,
|
||||
impl_def_id: <Self::Interner as Interner>::DefId,
|
||||
) -> Result<Option<<Self::Interner as Interner>::DefId>, NoSolution>;
|
||||
|
||||
fn is_transmutable(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
dst: <Self::Interner as Interner>::Ty,
|
||||
src: <Self::Interner as Interner>::Ty,
|
||||
assume: <Self::Interner as Interner>::Const,
|
||||
) -> Result<Certainty, NoSolution>;
|
||||
}
|
@ -4,6 +4,9 @@
|
||||
//! but were uplifted in the process of making the new trait solver generic.
|
||||
//! So if you got to this crate from the old solver, it's totally normal.
|
||||
|
||||
#![feature(let_chains)]
|
||||
|
||||
pub mod canonicalizer;
|
||||
pub mod infcx;
|
||||
pub mod resolve;
|
||||
pub mod solve;
|
||||
|
@ -1,27 +1,28 @@
|
||||
use crate::infcx::SolverDelegate;
|
||||
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::visit::TypeVisitableExt;
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EAGER RESOLUTION
|
||||
|
||||
/// Resolves ty, region, and const vars to their inferred values or their root vars.
|
||||
pub struct EagerResolver<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
|
||||
pub struct EagerResolver<'a, Infcx, I = <Infcx as SolverDelegate>::Interner>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
infcx: &'a Infcx,
|
||||
}
|
||||
|
||||
impl<'a, Infcx: InferCtxtLike> EagerResolver<'a, Infcx> {
|
||||
impl<'a, Infcx: SolverDelegate> EagerResolver<'a, Infcx> {
|
||||
pub fn new(infcx: &'a Infcx) -> Self {
|
||||
EagerResolver { infcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, Infcx> {
|
||||
impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, Infcx> {
|
||||
fn interner(&self) -> I {
|
||||
self.infcx.interner()
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
pub use rustc_type_ir::solve::*;
|
@ -15,17 +15,23 @@
|
||||
//! (3.) Otherwise, if we end with two rigid (non-projection) or infer types,
|
||||
//! relate them structurally.
|
||||
|
||||
use super::EvalCtxt;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
pub(super) fn compute_alias_relate_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, (I::Term, I::Term, ty::AliasRelationDirection)>,
|
||||
) -> QueryResult<I> {
|
||||
let tcx = self.interner();
|
||||
let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
|
||||
debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some());
|
@ -1,33 +1,26 @@
|
||||
//! Code shared by trait and projection goals for candidate assembly.
|
||||
|
||||
use derivative::Derivative;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::solve::inspect::ProbeKind;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause, QueryResult};
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{fast_reject, TypeFoldable};
|
||||
use rustc_middle::ty::{TypeVisitableExt, Upcast};
|
||||
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
|
||||
use rustc_type_ir::solve::{CandidateSource, CanonicalResponse};
|
||||
use rustc_type_ir::Interner;
|
||||
|
||||
use crate::solve::GoalSource;
|
||||
use crate::solve::{EvalCtxt, SolverMode};
|
||||
|
||||
pub(super) mod structural_traits;
|
||||
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::visit::TypeVisitableExt as _;
|
||||
use rustc_type_ir::{self as ty, Interner, Upcast as _};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::inspect::ProbeKind;
|
||||
use crate::solve::{
|
||||
BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
|
||||
MaybeCause, NoSolution, QueryResult, SolverMode,
|
||||
};
|
||||
|
||||
/// A candidate is a possible way to prove a goal.
|
||||
///
|
||||
/// It consists of both the `source`, which describes how that goal would be proven,
|
||||
/// and the `result` when using the given `source`.
|
||||
#[derive(Derivative)]
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(Debug(bound = ""), Clone(bound = ""))]
|
||||
pub(super) struct Candidate<I: Interner> {
|
||||
pub(super) source: CandidateSource<I>,
|
||||
@ -35,39 +28,42 @@ pub(super) struct Candidate<I: Interner> {
|
||||
}
|
||||
|
||||
/// Methods used to assemble candidates for either trait or projection goals.
|
||||
pub(super) trait GoalKind<'tcx>:
|
||||
TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
|
||||
pub(super) trait GoalKind<Infcx, I = <Infcx as SolverDelegate>::Interner>:
|
||||
TypeFoldable<I> + Copy + Eq + std::fmt::Display
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
fn self_ty(self) -> Ty<'tcx>;
|
||||
fn self_ty(self) -> I::Ty;
|
||||
|
||||
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
|
||||
fn trait_ref(self, tcx: I) -> ty::TraitRef<I>;
|
||||
|
||||
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self;
|
||||
fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self;
|
||||
|
||||
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
|
||||
fn trait_def_id(self, tcx: I) -> I::DefId;
|
||||
|
||||
/// Try equating an assumption predicate against a goal's predicate. If it
|
||||
/// holds, then execute the `then` callback, which should do any additional
|
||||
/// work, then produce a response (typically by executing
|
||||
/// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
|
||||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
source: CandidateSource<TyCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
source: CandidateSource<I>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// Consider a clause, which consists of a "assumption" and some "requirements",
|
||||
/// to satisfy a goal. If the requirements hold, then attempt to satisfy our
|
||||
/// goal by equating it with the assumption.
|
||||
fn probe_and_consider_implied_clause(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
parent_source: CandidateSource<TyCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
parent_source: CandidateSource<I>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
requirements: impl IntoIterator<Item = (GoalSource, Goal<I, I::Predicate>)>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, parent_source, goal, assumption, |ecx| {
|
||||
for (nested_source, goal) in requirements {
|
||||
ecx.add_goal(nested_source, goal);
|
||||
@ -80,15 +76,15 @@ pub(super) trait GoalKind<'tcx>:
|
||||
/// additionally checking all of the supertraits and object bounds to hold,
|
||||
/// since they're not implied by the well-formedness of the object type.
|
||||
fn probe_and_consider_object_bound_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
source: CandidateSource<TyCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
source: CandidateSource<I>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| {
|
||||
let tcx = ecx.interner();
|
||||
let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
|
||||
bug!("expected object type in `probe_and_consider_object_bound_candidate`");
|
||||
let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {
|
||||
panic!("expected object type in `probe_and_consider_object_bound_candidate`");
|
||||
};
|
||||
ecx.add_goals(
|
||||
GoalSource::ImplWhereBound,
|
||||
@ -104,10 +100,10 @@ pub(super) trait GoalKind<'tcx>:
|
||||
}
|
||||
|
||||
fn consider_impl_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
impl_def_id: I::DefId,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// If the predicate contained an error, we want to avoid emitting unnecessary trait
|
||||
/// errors but still want to emit errors for other trait goals. We have some special
|
||||
@ -116,85 +112,85 @@ pub(super) trait GoalKind<'tcx>:
|
||||
/// Trait goals always hold while projection goals never do. This is a bit arbitrary
|
||||
/// but prevents incorrect normalization while hiding any trait errors.
|
||||
fn consider_error_guaranteed_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
guar: I::ErrorGuaranteed,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A type implements an `auto trait` if its components do as well.
|
||||
///
|
||||
/// These components are given by built-in rules from
|
||||
/// [`structural_traits::instantiate_constituent_tys_for_auto_trait`].
|
||||
fn consider_auto_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A trait alias holds if the RHS traits and `where` clauses hold.
|
||||
fn consider_trait_alias_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A type is `Sized` if its tail component is `Sized`.
|
||||
///
|
||||
/// These components are given by built-in rules from
|
||||
/// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
|
||||
fn consider_builtin_sized_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
|
||||
///
|
||||
/// These components are given by built-in rules from
|
||||
/// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`].
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A type is `PointerLike` if we can compute its layout, and that layout
|
||||
/// matches the layout of `usize`.
|
||||
fn consider_builtin_pointer_like_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A type is a `FnPtr` if it is of `FnPtr` type.
|
||||
fn consider_builtin_fn_ptr_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
|
||||
/// family of traits where `A` is given by the signature of the type.
|
||||
fn consider_builtin_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
kind: ty::ClosureKind,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// An async closure is known to implement the `AsyncFn<A>` family of traits
|
||||
/// where `A` is given by the signature of the type.
|
||||
fn consider_builtin_async_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
kind: ty::ClosureKind,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
|
||||
/// is used internally to delay computation for async closures until after
|
||||
/// upvar analysis is performed in HIR typeck.
|
||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// `Tuple` is implemented if the `Self` type is a tuple.
|
||||
fn consider_builtin_tuple_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// `Pointee` is always implemented.
|
||||
///
|
||||
@ -202,65 +198,65 @@ pub(super) trait GoalKind<'tcx>:
|
||||
/// the built-in types. For structs, the metadata type is given by the struct
|
||||
/// tail.
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A coroutine (that comes from an `async` desugaring) is known to implement
|
||||
/// `Future<Output = O>`, where `O` is given by the coroutine's return type
|
||||
/// that was computed during type-checking.
|
||||
fn consider_builtin_future_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
||||
/// `Iterator<Item = O>`, where `O` is given by the generator's yield type
|
||||
/// that was computed during type-checking.
|
||||
fn consider_builtin_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
||||
/// `FusedIterator`
|
||||
fn consider_builtin_fused_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
fn consider_builtin_async_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
|
||||
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
|
||||
/// and return types of the coroutine computed during type-checking.
|
||||
fn consider_builtin_coroutine_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
fn consider_builtin_discriminant_kind_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
fn consider_builtin_async_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
fn consider_builtin_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
fn consider_builtin_transmute_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution>;
|
||||
|
||||
/// Consider (possibly several) candidates to upcast or unsize a type to another
|
||||
/// type, excluding the coercion of a sized type into a `dyn Trait`.
|
||||
@ -270,16 +266,20 @@ pub(super) trait GoalKind<'tcx>:
|
||||
/// otherwise recompute this for codegen. This is a bit of a mess but the
|
||||
/// easiest way to maintain the existing behavior for now.
|
||||
fn consider_structural_builtin_unsize_candidates(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Vec<Candidate<TyCtxt<'tcx>>>;
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Vec<Candidate<I>>;
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
) -> Vec<Candidate<TyCtxt<'tcx>>> {
|
||||
goal: Goal<I, G>,
|
||||
) -> Vec<Candidate<I>> {
|
||||
let Ok(normalized_self_ty) =
|
||||
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
|
||||
else {
|
||||
@ -291,7 +291,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
|
||||
}
|
||||
|
||||
let goal: Goal<'tcx, G> = goal.with(
|
||||
let goal: Goal<I, G> = goal.with(
|
||||
self.interner(),
|
||||
goal.predicate.with_self_ty(self.interner(), normalized_self_ty),
|
||||
);
|
||||
@ -301,7 +301,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
|
||||
let mut candidates = vec![];
|
||||
|
||||
self.assemble_non_blanket_impl_candidates(goal, &mut candidates);
|
||||
self.assemble_impl_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_builtin_impl_candidates(goal, &mut candidates);
|
||||
|
||||
@ -309,8 +309,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
|
||||
self.assemble_object_bound_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_blanket_impl_candidates(goal, &mut candidates);
|
||||
|
||||
self.assemble_param_env_candidates(goal, &mut candidates);
|
||||
|
||||
match self.solver_mode() {
|
||||
@ -326,7 +324,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
pub(super) fn forced_ambiguity(
|
||||
&mut self,
|
||||
cause: MaybeCause,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
// This may fail if `try_evaluate_added_goals` overflows because it
|
||||
// fails to reach a fixpoint but ends up getting an error after
|
||||
// running for some additional step.
|
||||
@ -339,149 +337,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>(
|
||||
fn assemble_impl_candidates<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let tcx = self.interner();
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
|
||||
let mut consider_impls_for_simplified_type = |simp| {
|
||||
if let Some(impls_for_type) = trait_impls.non_blanket_impls().get(&simp) {
|
||||
for &impl_def_id in impls_for_type {
|
||||
// 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) => (),
|
||||
}
|
||||
tcx.for_each_relevant_impl(
|
||||
goal.predicate.trait_def_id(tcx),
|
||||
goal.predicate.self_ty(),
|
||||
|impl_def_id| {
|
||||
// For every `default impl`, there's always a non-default `impl`
|
||||
// that will *also* apply. There's no reason to register a candidate
|
||||
// for this impl, since it is *not* proof that the trait goal holds.
|
||||
if tcx.impl_is_default(impl_def_id) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(..)
|
||||
| ty::CoroutineClosure(..)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::Never
|
||||
| ty::Tuple(_) => {
|
||||
let simp =
|
||||
fast_reject::simplify_type(tcx, self_ty, TreatParams::ForLookup).unwrap();
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
|
||||
// HACK: For integer and float variables we have to manually look at all impls
|
||||
// which have some integer or float as a self type.
|
||||
ty::Infer(ty::IntVar(_)) => {
|
||||
use ty::IntTy::*;
|
||||
use ty::UintTy::*;
|
||||
// This causes a compiler error if any new integer kinds are added.
|
||||
let (I8 | I16 | I32 | I64 | I128 | Isize): ty::IntTy;
|
||||
let (U8 | U16 | U32 | U64 | U128 | Usize): ty::UintTy;
|
||||
let possible_integers = [
|
||||
// signed integers
|
||||
SimplifiedType::Int(I8),
|
||||
SimplifiedType::Int(I16),
|
||||
SimplifiedType::Int(I32),
|
||||
SimplifiedType::Int(I64),
|
||||
SimplifiedType::Int(I128),
|
||||
SimplifiedType::Int(Isize),
|
||||
// unsigned integers
|
||||
SimplifiedType::Uint(U8),
|
||||
SimplifiedType::Uint(U16),
|
||||
SimplifiedType::Uint(U32),
|
||||
SimplifiedType::Uint(U64),
|
||||
SimplifiedType::Uint(U128),
|
||||
SimplifiedType::Uint(Usize),
|
||||
];
|
||||
for simp in possible_integers {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
match G::consider_impl_candidate(self, goal, impl_def_id) {
|
||||
Ok(candidate) => candidates.push(candidate),
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Infer(ty::FloatVar(_)) => {
|
||||
// This causes a compiler error if any new float kinds are added.
|
||||
let (ty::FloatTy::F16 | ty::FloatTy::F32 | ty::FloatTy::F64 | ty::FloatTy::F128);
|
||||
let possible_floats = [
|
||||
SimplifiedType::Float(ty::FloatTy::F16),
|
||||
SimplifiedType::Float(ty::FloatTy::F32),
|
||||
SimplifiedType::Float(ty::FloatTy::F64),
|
||||
SimplifiedType::Float(ty::FloatTy::F128),
|
||||
];
|
||||
|
||||
for simp in possible_floats {
|
||||
consider_impls_for_simplified_type(simp);
|
||||
}
|
||||
}
|
||||
|
||||
// The only traits applying to aliases and placeholders are blanket impls.
|
||||
//
|
||||
// Impls which apply to an alias after normalization are handled by
|
||||
// `assemble_candidates_after_normalizing_self_ty`.
|
||||
ty::Alias(_, _) | ty::Placeholder(..) | ty::Error(_) => (),
|
||||
|
||||
// FIXME: These should ideally not exist as a self type. It would be nice for
|
||||
// the builtin auto trait impls of coroutines to instead directly recurse
|
||||
// into the witness.
|
||||
ty::CoroutineWitness(..) => (),
|
||||
|
||||
// These variants should not exist as a self type.
|
||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>(
|
||||
fn assemble_builtin_impl_candidates<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
) {
|
||||
let tcx = self.interner();
|
||||
let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx));
|
||||
for &impl_def_id in trait_impls.blanket_impls() {
|
||||
// For every `default impl`, there's always a non-default `impl`
|
||||
// that will *also* apply. There's no reason to register a candidate
|
||||
// for this impl, since it is *not* proof that the trait goal holds.
|
||||
if tcx.defaultness(impl_def_id).is_default() {
|
||||
return;
|
||||
}
|
||||
|
||||
match G::consider_impl_candidate(self, goal, impl_def_id) {
|
||||
Ok(candidate) => candidates.push(candidate),
|
||||
Err(NoSolution) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let tcx = self.interner();
|
||||
let trait_def_id = goal.predicate.trait_def_id(tcx);
|
||||
@ -499,43 +384,43 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
G::consider_auto_trait_candidate(self, goal)
|
||||
} else if tcx.trait_is_alias(trait_def_id) {
|
||||
G::consider_trait_alias_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Sized) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) {
|
||||
G::consider_builtin_sized_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Copy)
|
||||
|| tcx.is_lang_item(trait_def_id, LangItem::Clone)
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy)
|
||||
|| tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone)
|
||||
{
|
||||
G::consider_builtin_copy_clone_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::PointerLike) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) {
|
||||
G::consider_builtin_pointer_like_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::FnPtrTrait) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) {
|
||||
G::consider_builtin_fn_ptr_trait_candidate(self, goal)
|
||||
} else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) {
|
||||
G::consider_builtin_fn_trait_candidates(self, goal, kind)
|
||||
} else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) {
|
||||
G::consider_builtin_async_fn_trait_candidates(self, goal, kind)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::AsyncFnKindHelper) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) {
|
||||
G::consider_builtin_async_fn_kind_helper_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Tuple) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) {
|
||||
G::consider_builtin_tuple_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) {
|
||||
G::consider_builtin_pointee_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Future) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) {
|
||||
G::consider_builtin_future_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Iterator) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) {
|
||||
G::consider_builtin_iterator_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::FusedIterator) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) {
|
||||
G::consider_builtin_fused_iterator_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::AsyncIterator) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) {
|
||||
G::consider_builtin_async_iterator_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) {
|
||||
G::consider_builtin_coroutine_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) {
|
||||
G::consider_builtin_discriminant_kind_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::AsyncDestruct) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) {
|
||||
G::consider_builtin_async_destruct_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::Destruct) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) {
|
||||
G::consider_builtin_destruct_candidate(self, goal)
|
||||
} else if tcx.is_lang_item(trait_def_id, LangItem::TransmuteTrait) {
|
||||
} else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) {
|
||||
G::consider_builtin_transmute_candidate(self, goal)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
@ -545,18 +430,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
|
||||
// There may be multiple unsize candidates for a trait with several supertraits:
|
||||
// `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
|
||||
if tcx.is_lang_item(trait_def_id, LangItem::Unsize) {
|
||||
if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) {
|
||||
candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal));
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn assemble_param_env_candidates<G: GoalKind<'tcx>>(
|
||||
fn assemble_param_env_candidates<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
|
||||
for (i, assumption) in goal.param_env.caller_bounds().into_iter().enumerate() {
|
||||
candidates.extend(G::probe_and_consider_implied_clause(
|
||||
self,
|
||||
CandidateSource::ParamEnv(i),
|
||||
@ -568,10 +453,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
|
||||
fn assemble_alias_bound_candidates<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
|
||||
ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
|
||||
@ -587,13 +472,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// If so, continue searching by recursively calling after normalization.
|
||||
// FIXME: This may recurse infinitely, but I can't seem to trigger it without
|
||||
// hitting another overflow error something. Add a depth parameter needed later.
|
||||
fn assemble_alias_bound_candidates_recur<G: GoalKind<'tcx>>(
|
||||
fn assemble_alias_bound_candidates_recur<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
self_ty: Ty<'tcx>,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
self_ty: I::Ty,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let (kind, alias_ty) = match *self_ty.kind() {
|
||||
let (kind, alias_ty) = match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
@ -621,7 +506,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| ty::Error(_) => return,
|
||||
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => {
|
||||
bug!("unexpected self type for `{goal:?}`")
|
||||
panic!("unexpected self type for `{goal:?}`")
|
||||
}
|
||||
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
@ -638,16 +523,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
|
||||
ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
|
||||
ty::Alias(ty::Inherent | ty::Weak, _) => {
|
||||
self.interner().sess.dcx().span_delayed_bug(
|
||||
DUMMY_SP,
|
||||
format!("could not normalize {self_ty}, it is not WF"),
|
||||
);
|
||||
self.interner().delay_bug(format!("could not normalize {self_ty:?}, it is not WF"));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
for assumption in
|
||||
self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args)
|
||||
for assumption in self
|
||||
.interner()
|
||||
.item_bounds(alias_ty.def_id)
|
||||
.iter_instantiated(self.interner(), &alias_ty.args)
|
||||
{
|
||||
candidates.extend(G::probe_and_consider_implied_clause(
|
||||
self,
|
||||
@ -672,18 +556,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
|
||||
fn assemble_object_bound_candidates<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let tcx = self.interner();
|
||||
if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object {
|
||||
if !tcx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(tcx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let bounds = match *self_ty.kind() {
|
||||
let bounds = match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
@ -711,12 +595,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| ty::Error(_) => return,
|
||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
|
||||
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
|
||||
| ty::Bound(..) => panic!("unexpected self type for `{goal:?}`"),
|
||||
ty::Dynamic(bounds, ..) => bounds,
|
||||
};
|
||||
|
||||
// Do not consider built-in object impls for non-object-safe types.
|
||||
if bounds.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) {
|
||||
if bounds.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -745,7 +629,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// a projection goal.
|
||||
if let Some(principal) = bounds.principal() {
|
||||
let principal_trait_ref = principal.with_self_ty(tcx, self_ty);
|
||||
for (idx, assumption) in supertraits(self.interner(), principal_trait_ref).enumerate() {
|
||||
for (idx, assumption) in
|
||||
Infcx::elaborate_supertraits(tcx, principal_trait_ref).enumerate()
|
||||
{
|
||||
candidates.extend(G::probe_and_consider_object_bound_candidate(
|
||||
self,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)),
|
||||
@ -763,10 +649,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// To do so we add an ambiguous candidate in case such an unknown impl could
|
||||
/// apply to the current goal.
|
||||
#[instrument(level = "trace", skip_all)]
|
||||
fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>(
|
||||
fn assemble_coherence_unknowable_candidates<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let tcx = self.interner();
|
||||
|
||||
@ -792,13 +678,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// to improve this however. However, this should make it fairly straightforward to refine
|
||||
// the filtering going forward, so it seems alright-ish for now.
|
||||
#[instrument(level = "debug", skip(self, goal))]
|
||||
fn discard_impls_shadowed_by_env<G: GoalKind<'tcx>>(
|
||||
fn discard_impls_shadowed_by_env<G: GoalKind<Infcx>>(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, G>,
|
||||
candidates: &mut Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
goal: Goal<I, G>,
|
||||
candidates: &mut Vec<Candidate<I>>,
|
||||
) {
|
||||
let tcx = self.interner();
|
||||
let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
|
||||
let trait_goal: Goal<I, ty::TraitPredicate<I>> =
|
||||
goal.with(tcx, goal.predicate.trait_ref(tcx));
|
||||
|
||||
let mut trait_candidates_from_env = vec![];
|
||||
@ -823,7 +709,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
false
|
||||
}
|
||||
CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => true,
|
||||
CandidateSource::CoherenceUnknowable => bug!("uh oh"),
|
||||
CandidateSource::CoherenceUnknowable => panic!("uh oh"),
|
||||
});
|
||||
}
|
||||
// If it is still ambiguous we instead just force the whole goal
|
||||
@ -841,10 +727,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// to somehow try to merge the candidates into one. If that fails, we return
|
||||
/// ambiguity.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub(super) fn merge_candidates(
|
||||
&mut self,
|
||||
candidates: Vec<Candidate<TyCtxt<'tcx>>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
pub(super) fn merge_candidates(&mut self, candidates: Vec<Candidate<I>>) -> QueryResult<I> {
|
||||
// First try merging all candidates. This is complete and fully sound.
|
||||
let responses = candidates.iter().map(|c| c.result).collect::<Vec<_>>();
|
||||
if let Some(result) = self.try_merge_responses(&responses) {
|
@ -3,26 +3,24 @@
|
||||
|
||||
use rustc_ast_ir::{Movability, Mutability};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_next_trait_solver::solve::{Goal, NoSolution};
|
||||
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast};
|
||||
use rustc_type_ir::{self as ty, Interner, Upcast as _};
|
||||
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::solve::EvalCtxt;
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::{EvalCtxt, Goal, NoSolution};
|
||||
|
||||
// Calculates the constituent types of a type for `auto trait` purposes.
|
||||
//
|
||||
// For types with an "existential" binder, i.e. coroutine witnesses, we also
|
||||
// instantiate the binder with placeholders eagerly.
|
||||
#[instrument(level = "trace", skip(ecx), ret)]
|
||||
pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<Infcx, I>(
|
||||
ecx: &EvalCtxt<'_, Infcx>,
|
||||
ty: I::Ty,
|
||||
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
let tcx = ecx.interner();
|
||||
@ -108,7 +106,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<Infcx, I>(
|
||||
ty: I::Ty,
|
||||
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
match ty.kind() {
|
||||
@ -176,7 +174,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<Infcx,
|
||||
ty: I::Ty,
|
||||
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
match ty.kind() {
|
||||
@ -663,7 +661,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<Infcx, I>(
|
||||
object_bounds: I::BoundExistentialPredicates,
|
||||
) -> Vec<Goal<I, I::Predicate>>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
let tcx = ecx.interner();
|
||||
@ -712,14 +710,14 @@ where
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
|
||||
struct ReplaceProjectionWith<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> {
|
||||
ecx: &'a EvalCtxt<'a, Infcx>,
|
||||
param_env: I::ParamEnv,
|
||||
mapping: FxHashMap<I::DefId, ty::Binder<I, ty::ProjectionPredicate<I>>>,
|
||||
nested: Vec<Goal<I, I::Predicate>>,
|
||||
}
|
||||
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||
impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I>
|
||||
for ReplaceProjectionWith<'_, Infcx, I>
|
||||
{
|
||||
fn interner(&self) -> I {
|
||||
@ -744,7 +742,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
|
||||
)
|
||||
.expect("expected to be able to unify goal projection with dyn's projection"),
|
||||
);
|
||||
proj.term.expect_type()
|
||||
proj.term.expect_ty()
|
||||
} else {
|
||||
ty.super_fold_with(self)
|
||||
}
|
@ -8,58 +8,53 @@
|
||||
//! section of the [rustc-dev-guide][c].
|
||||
//!
|
||||
//! [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
|
||||
use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
|
||||
use crate::solve::eval_ctxt::NestedGoals;
|
||||
use crate::solve::{
|
||||
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::resolve::EagerResolver;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_type_ir::CanonicalVarValues;
|
||||
use rustc_type_ir::{InferCtxtLike, Interner};
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
|
||||
trait ResponseT<'tcx> {
|
||||
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>>;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_type_ir::fold::TypeFoldable;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
use crate::canonicalizer::{CanonicalizeMode, Canonicalizer};
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::resolve::EagerResolver;
|
||||
use crate::solve::eval_ctxt::NestedGoals;
|
||||
use crate::solve::inspect;
|
||||
use crate::solve::{
|
||||
response_no_constraints_raw, CanonicalInput, CanonicalResponse, Certainty, EvalCtxt,
|
||||
ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution,
|
||||
PredefinedOpaquesData, QueryInput, QueryResult, Response,
|
||||
};
|
||||
|
||||
trait ResponseT<I: Interner> {
|
||||
fn var_values(&self) -> CanonicalVarValues<I>;
|
||||
}
|
||||
|
||||
impl<'tcx> ResponseT<'tcx> for Response<TyCtxt<'tcx>> {
|
||||
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> {
|
||||
impl<I: Interner> ResponseT<I> for Response<I> {
|
||||
fn var_values(&self) -> CanonicalVarValues<I> {
|
||||
self.var_values
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> {
|
||||
fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> {
|
||||
impl<I: Interner, T> ResponseT<I> for inspect::State<I, T> {
|
||||
fn var_values(&self) -> CanonicalVarValues<I> {
|
||||
self.var_values
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
/// Canonicalizes the goal remembering the original values
|
||||
/// for each bound variable.
|
||||
pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>(
|
||||
pub(super) fn canonicalize_goal<T: TypeFoldable<I>>(
|
||||
&self,
|
||||
goal: Goal<'tcx, T>,
|
||||
) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx, T>) {
|
||||
goal: Goal<I, T>,
|
||||
) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) {
|
||||
let opaque_types = self.infcx.clone_opaque_types_for_query_response();
|
||||
let (goal, opaque_types) =
|
||||
(goal, opaque_types).fold_with(&mut EagerResolver::new(self.infcx));
|
||||
@ -89,7 +84,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
|
||||
&mut self,
|
||||
certainty: Certainty,
|
||||
) -> QueryResult<'tcx> {
|
||||
) -> QueryResult<I> {
|
||||
self.inspect.make_canonical_response(certainty);
|
||||
|
||||
let goals_certainty = self.try_evaluate_added_goals()?;
|
||||
@ -102,8 +97,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
|
||||
// We only check for leaks from universes which were entered inside
|
||||
// of the query.
|
||||
self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
|
||||
trace!(?e, "failed the leak check");
|
||||
self.infcx.leak_check(self.max_input_universe).map_err(|NoSolution| {
|
||||
trace!("failed the leak check");
|
||||
NoSolution
|
||||
})?;
|
||||
|
||||
@ -119,7 +114,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
if cfg!(debug_assertions) {
|
||||
assert!(normalizes_to_goals.is_empty());
|
||||
if goals.is_empty() {
|
||||
assert_matches!(goals_certainty, Certainty::Yes);
|
||||
assert!(matches!(goals_certainty, Certainty::Yes));
|
||||
}
|
||||
}
|
||||
(certainty, NestedNormalizationGoals(goals))
|
||||
@ -158,7 +153,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
pub(in crate::solve) fn make_ambiguous_response_no_constraints(
|
||||
&self,
|
||||
maybe_cause: MaybeCause,
|
||||
) -> CanonicalResponse<'tcx> {
|
||||
) -> CanonicalResponse<I> {
|
||||
response_no_constraints_raw(
|
||||
self.interner(),
|
||||
self.max_input_universe,
|
||||
@ -178,8 +173,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
fn compute_external_query_constraints(
|
||||
&self,
|
||||
certainty: Certainty,
|
||||
normalization_nested_goals: NestedNormalizationGoals<TyCtxt<'tcx>>,
|
||||
) -> ExternalConstraintsData<TyCtxt<'tcx>> {
|
||||
normalization_nested_goals: NestedNormalizationGoals<I>,
|
||||
) -> ExternalConstraintsData<I> {
|
||||
// We only return region constraints once the certainty is `Yes`. This
|
||||
// is necessary as we may drop nested goals on ambiguity, which may result
|
||||
// in unconstrained inference variables in the region constraints. It also
|
||||
@ -189,26 +184,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// `tests/ui/higher-ranked/leak-check/leak-check-in-selection-5-ambig.rs` and
|
||||
// `tests/ui/higher-ranked/leak-check/leak-check-in-selection-6-ambig-unify.rs`.
|
||||
let region_constraints = if certainty == Certainty::Yes {
|
||||
// Cannot use `take_registered_region_obligations` as we may compute the response
|
||||
// inside of a `probe` whenever we have multiple choices inside of the solver.
|
||||
let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned();
|
||||
let QueryRegionConstraints { outlives, member_constraints } =
|
||||
self.infcx.with_region_constraints(|region_constraints| {
|
||||
make_query_region_constraints(
|
||||
self.interner(),
|
||||
region_obligations.iter().map(|r_o| {
|
||||
(r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())
|
||||
}),
|
||||
region_constraints,
|
||||
)
|
||||
});
|
||||
assert_eq!(member_constraints, vec![]);
|
||||
let mut seen = FxHashSet::default();
|
||||
outlives
|
||||
.into_iter()
|
||||
.filter(|(outlives, _)| seen.insert(*outlives))
|
||||
.map(|(outlives, _origin)| outlives)
|
||||
.collect()
|
||||
self.infcx.make_deduplicated_outlives_constraints()
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
@ -238,10 +214,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// the `normalization_nested_goals`
|
||||
pub(super) fn instantiate_and_apply_query_response(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
original_values: Vec<ty::GenericArg<'tcx>>,
|
||||
response: CanonicalResponse<'tcx>,
|
||||
) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty) {
|
||||
param_env: I::ParamEnv,
|
||||
original_values: Vec<I::GenericArg>,
|
||||
response: CanonicalResponse<I>,
|
||||
) -> (NestedNormalizationGoals<I>, Certainty) {
|
||||
let instantiation = Self::compute_query_response_instantiation_values(
|
||||
self.infcx,
|
||||
&original_values,
|
||||
@ -249,7 +225,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
);
|
||||
|
||||
let Response { var_values, external_constraints, certainty } =
|
||||
response.instantiate(self.interner(), &instantiation);
|
||||
self.infcx.instantiate_canonical(response, instantiation);
|
||||
|
||||
Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values);
|
||||
|
||||
@ -257,7 +233,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
region_constraints,
|
||||
opaque_types,
|
||||
normalization_nested_goals,
|
||||
} = external_constraints.deref();
|
||||
} = &*external_constraints;
|
||||
self.register_region_constraints(region_constraints);
|
||||
self.register_new_opaque_types(opaque_types);
|
||||
(normalization_nested_goals.clone(), certainty)
|
||||
@ -266,11 +242,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// This returns the canoncial variable values to instantiate the bound variables of
|
||||
/// the canonical response. This depends on the `original_values` for the
|
||||
/// bound variables.
|
||||
fn compute_query_response_instantiation_values<T: ResponseT<'tcx>>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
original_values: &[ty::GenericArg<'tcx>],
|
||||
response: &Canonical<'tcx, T>,
|
||||
) -> CanonicalVarValues<TyCtxt<'tcx>> {
|
||||
fn compute_query_response_instantiation_values<T: ResponseT<I>>(
|
||||
infcx: &Infcx,
|
||||
original_values: &[I::GenericArg],
|
||||
response: &Canonical<I, T>,
|
||||
) -> CanonicalVarValues<I> {
|
||||
// FIXME: Longterm canonical queries should deal with all placeholders
|
||||
// created inside of the query directly instead of returning them to the
|
||||
// caller.
|
||||
@ -292,35 +268,35 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// inference variable of the input right away, which is more performant.
|
||||
let mut opt_values = IndexVec::from_elem_n(None, response.variables.len());
|
||||
for (original_value, result_value) in iter::zip(original_values, var_values.var_values) {
|
||||
match result_value.unpack() {
|
||||
GenericArgKind::Type(t) => {
|
||||
if let &ty::Bound(debruijn, b) = t.kind() {
|
||||
match result_value.kind() {
|
||||
ty::GenericArgKind::Type(t) => {
|
||||
if let ty::Bound(debruijn, b) = t.kind() {
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[b.var] = Some(*original_value);
|
||||
opt_values[b.var()] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
GenericArgKind::Lifetime(r) => {
|
||||
if let ty::ReBound(debruijn, br) = *r {
|
||||
ty::GenericArgKind::Lifetime(r) => {
|
||||
if let ty::ReBound(debruijn, br) = r.kind() {
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[br.var] = Some(*original_value);
|
||||
opt_values[br.var()] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
GenericArgKind::Const(c) => {
|
||||
if let ty::ConstKind::Bound(debruijn, b) = c.kind() {
|
||||
ty::GenericArgKind::Const(c) => {
|
||||
if let ty::ConstKind::Bound(debruijn, bv) = c.kind() {
|
||||
assert_eq!(debruijn, ty::INNERMOST);
|
||||
opt_values[b] = Some(*original_value);
|
||||
opt_values[bv.var()] = Some(*original_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let var_values = infcx.tcx.mk_args_from_iter(response.variables.iter().enumerate().map(
|
||||
|(index, info)| {
|
||||
let var_values = infcx.interner().mk_args_from_iter(
|
||||
response.variables.into_iter().enumerate().map(|(index, info)| {
|
||||
if info.universe() != ty::UniverseIndex::ROOT {
|
||||
// A variable from inside a binder of the query. While ideally these shouldn't
|
||||
// exist at all (see the FIXME at the start of this method), we have to deal with
|
||||
// them for now.
|
||||
infcx.instantiate_canonical_var(DUMMY_SP, info, |idx| {
|
||||
infcx.instantiate_canonical_var_with_infer(info, |idx| {
|
||||
ty::UniverseIndex::from(prev_universe.index() + idx.index())
|
||||
})
|
||||
} else if info.is_existential() {
|
||||
@ -331,18 +307,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// more placeholders then they should be able to. However the inference variables have
|
||||
// to "come from somewhere", so by equating them with the original values of the caller
|
||||
// later on, we pull them down into their correct universe again.
|
||||
if let Some(v) = opt_values[BoundVar::from_usize(index)] {
|
||||
if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] {
|
||||
v
|
||||
} else {
|
||||
infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe)
|
||||
infcx.instantiate_canonical_var_with_infer(info, |_| prev_universe)
|
||||
}
|
||||
} else {
|
||||
// For placeholders which were already part of the input, we simply map this
|
||||
// universal bound variable back the placeholder of the input.
|
||||
original_values[info.expect_placeholder_index()]
|
||||
}
|
||||
},
|
||||
));
|
||||
}),
|
||||
);
|
||||
|
||||
CanonicalVarValues { var_values }
|
||||
}
|
||||
@ -361,40 +337,35 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// always relate them structurally here.
|
||||
#[instrument(level = "trace", skip(infcx))]
|
||||
fn unify_query_var_values(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
original_values: &[ty::GenericArg<'tcx>],
|
||||
var_values: CanonicalVarValues<TyCtxt<'tcx>>,
|
||||
infcx: &Infcx,
|
||||
param_env: I::ParamEnv,
|
||||
original_values: &[I::GenericArg],
|
||||
var_values: CanonicalVarValues<I>,
|
||||
) {
|
||||
assert_eq!(original_values.len(), var_values.len());
|
||||
|
||||
let cause = ObligationCause::dummy();
|
||||
for (&orig, response) in iter::zip(original_values, var_values.var_values) {
|
||||
let InferOk { value: (), obligations } = infcx
|
||||
.at(&cause, param_env)
|
||||
.eq_structurally_relating_aliases(orig, response)
|
||||
.unwrap();
|
||||
assert!(obligations.is_empty());
|
||||
let goals = infcx.eq_structurally_relating_aliases(param_env, orig, response).unwrap();
|
||||
assert!(goals.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
fn register_region_constraints(
|
||||
&mut self,
|
||||
outlives: &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>],
|
||||
outlives: &[ty::OutlivesPredicate<I, I::GenericArg>],
|
||||
) {
|
||||
for &ty::OutlivesPredicate(lhs, rhs) in outlives {
|
||||
match lhs.unpack() {
|
||||
GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
|
||||
GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
|
||||
GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"),
|
||||
match lhs.kind() {
|
||||
ty::GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs),
|
||||
ty::GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs),
|
||||
ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) {
|
||||
fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<I>, I::Ty)]) {
|
||||
for &(key, ty) in opaque_types {
|
||||
let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP };
|
||||
self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty);
|
||||
self.infcx.inject_new_hidden_type_unchecked(key, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -410,7 +381,7 @@ pub(in crate::solve) fn make_canonical_state<Infcx, T, I>(
|
||||
data: T,
|
||||
) -> inspect::CanonicalState<I, T>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
T: TypeFoldable<I>,
|
||||
{
|
||||
@ -425,45 +396,33 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
// FIXME: needs to be pub to be accessed by downstream
|
||||
// `rustc_trait_selection::solve::inspect::analyse`.
|
||||
pub fn instantiate_canonical_state<Infcx, I, T: TypeFoldable<I>>(
|
||||
infcx: &Infcx,
|
||||
span: Infcx::Span,
|
||||
param_env: I::ParamEnv,
|
||||
orig_values: &mut Vec<I::GenericArg>,
|
||||
state: inspect::CanonicalState<I, T>,
|
||||
) -> T
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
// 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(),
|
||||
};
|
||||
|
||||
for &arg in &state.value.var_values.var_values[orig_values.len()..state.value.var_values.len()]
|
||||
{
|
||||
// FIXME: This is so ugly.
|
||||
let unconstrained = infcx.fresh_var_for_kind_with_span(arg, span);
|
||||
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);
|
||||
let inspect::State { var_values, data } = infcx.instantiate_canonical(state, instantiation);
|
||||
|
||||
EvalCtxt::unify_query_var_values(infcx, param_env, orig_values, var_values);
|
||||
data
|
@ -1,41 +1,30 @@
|
||||
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, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_type_ir::fold::TypeSuperFoldable;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
|
||||
use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
|
||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use crate::traits::coherence;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
|
||||
use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
|
||||
use rustc_type_ir::{self as ty, CanonicalVarValues, Interner};
|
||||
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
use super::inspect::ProofTreeBuilder;
|
||||
use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT};
|
||||
use super::{search_graph::SearchGraph, Goal};
|
||||
use super::{GoalSource, SolverMode};
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::inspect::{self, ProofTreeBuilder};
|
||||
use crate::solve::search_graph::SearchGraph;
|
||||
use crate::solve::{
|
||||
search_graph, CanonicalInput, CanonicalResponse, Certainty, Goal, GoalEvaluationKind,
|
||||
GoalSource, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData,
|
||||
QueryResult, SolverMode, FIXPOINT_STEP_LIMIT,
|
||||
};
|
||||
|
||||
pub(super) mod canonical;
|
||||
mod probe;
|
||||
|
||||
pub struct EvalCtxt<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner>
|
||||
pub struct EvalCtxt<'a, Infcx, I = <Infcx as SolverDelegate>::Interner>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
/// The inference context that backs (mostly) inference and placeholder terms
|
||||
@ -112,9 +101,9 @@ pub struct NestedGoals<I: Interner> {
|
||||
///
|
||||
/// Forgetting to replace the RHS with a fresh inference variable when we evaluate
|
||||
/// this goal results in an ICE..
|
||||
pub normalizes_to_goals: Vec<ir::solve::Goal<I, ir::NormalizesTo<I>>>,
|
||||
pub normalizes_to_goals: Vec<Goal<I, ty::NormalizesTo<I>>>,
|
||||
/// The rest of the goals which have not yet processed or remain ambiguous.
|
||||
pub goals: Vec<(GoalSource, ir::solve::Goal<I, I::Predicate>)>,
|
||||
pub goals: Vec<(GoalSource, Goal<I, I::Predicate>)>,
|
||||
}
|
||||
|
||||
impl<I: Interner> NestedGoals<I> {
|
||||
@ -127,14 +116,36 @@ impl<I: Interner> NestedGoals<I> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
|
||||
#[derive(PartialEq, Eq, Debug, Hash, HashStable_NoContext, Clone, Copy)]
|
||||
pub enum GenerateProofTree {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
#[extension(pub trait InferCtxtEvalExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
pub trait SolverDelegateEvalExt: SolverDelegate {
|
||||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<Self::Interner>>);
|
||||
|
||||
// FIXME: This is only exposed because we need to use it in `analyse.rs`
|
||||
// which is not yet uplifted. Once that's done, we should remove this.
|
||||
fn evaluate_root_goal_raw(
|
||||
&self,
|
||||
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (
|
||||
Result<(NestedNormalizationGoals<Self::Interner>, bool, Certainty), NoSolution>,
|
||||
Option<inspect::GoalEvaluation<Self::Interner>>,
|
||||
);
|
||||
}
|
||||
|
||||
impl<Infcx, I> SolverDelegateEvalExt for Infcx
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
/// Evaluates a goal from **outside** of the trait solver.
|
||||
///
|
||||
/// Using this while inside of the solver is wrong as it uses a new
|
||||
@ -142,17 +153,34 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn evaluate_root_goal(
|
||||
&self,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>)
|
||||
{
|
||||
) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<I>>) {
|
||||
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
|
||||
ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn evaluate_root_goal_raw(
|
||||
&self,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
) -> (
|
||||
Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution>,
|
||||
Option<inspect::GoalEvaluation<I>>,
|
||||
) {
|
||||
EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
|
||||
ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
impl<'a, Infcx, I> EvalCtxt<'a, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
pub(super) fn solver_mode(&self) -> SolverMode {
|
||||
self.search_graph.solver_mode()
|
||||
}
|
||||
@ -163,14 +191,13 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
|
||||
/// Creates a root evaluation context and search graph. This should only be
|
||||
/// used from outside of any evaluation, and other methods should be preferred
|
||||
/// over using this manually (such as [`InferCtxtEvalExt::evaluate_root_goal`]).
|
||||
/// over using this manually (such as [`SolverDelegateEvalExt::evaluate_root_goal`]).
|
||||
pub(super) fn enter_root<R>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
infcx: &Infcx,
|
||||
generate_proof_tree: GenerateProofTree,
|
||||
f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> R,
|
||||
) -> (R, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) {
|
||||
let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
|
||||
let mut search_graph = search_graph::SearchGraph::new(mode);
|
||||
f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> R,
|
||||
) -> (R, Option<inspect::GoalEvaluation<I>>) {
|
||||
let mut search_graph = search_graph::SearchGraph::new(infcx.solver_mode());
|
||||
|
||||
let mut ecx = EvalCtxt {
|
||||
infcx,
|
||||
@ -181,10 +208,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
// Only relevant when canonicalizing the response,
|
||||
// which we don't do within this evaluation context.
|
||||
predefined_opaques_in_body: infcx
|
||||
.tcx
|
||||
.interner()
|
||||
.mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
|
||||
max_input_universe: ty::UniverseIndex::ROOT,
|
||||
variables: ty::List::empty(),
|
||||
variables: Default::default(),
|
||||
var_values: CanonicalVarValues::dummy(),
|
||||
is_normalizes_to_goal: false,
|
||||
tainted: Ok(()),
|
||||
@ -210,21 +237,14 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
/// This function takes care of setting up the inference context, setting the anchor,
|
||||
/// and registering opaques from the canonicalized input.
|
||||
fn enter_canonical<R>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
|
||||
canonical_input: CanonicalInput<'tcx>,
|
||||
canonical_goal_evaluation: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
|
||||
f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
|
||||
tcx: I,
|
||||
search_graph: &'a mut search_graph::SearchGraph<I>,
|
||||
canonical_input: CanonicalInput<I>,
|
||||
canonical_goal_evaluation: &mut ProofTreeBuilder<Infcx>,
|
||||
f: impl FnOnce(&mut EvalCtxt<'_, Infcx>, Goal<I, I::Predicate>) -> R,
|
||||
) -> R {
|
||||
let intercrate = match search_graph.solver_mode() {
|
||||
SolverMode::Normal => false,
|
||||
SolverMode::Coherence => true,
|
||||
};
|
||||
let (ref infcx, input, var_values) = tcx
|
||||
.infer_ctxt()
|
||||
.intercrate(intercrate)
|
||||
.with_next_trait_solver(true)
|
||||
.build_with_canonical(DUMMY_SP, &canonical_input);
|
||||
let (ref infcx, input, var_values) =
|
||||
SolverDelegate::build_with_canonical(tcx, search_graph.solver_mode(), &canonical_input);
|
||||
|
||||
let mut ecx = EvalCtxt {
|
||||
infcx,
|
||||
@ -240,8 +260,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
};
|
||||
|
||||
for &(key, ty) in &input.predefined_opaques_in_body.opaque_types {
|
||||
let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP };
|
||||
ecx.infcx.inject_new_hidden_type_unchecked(key, hidden_ty);
|
||||
ecx.infcx.inject_new_hidden_type_unchecked(key, ty);
|
||||
}
|
||||
|
||||
if !ecx.nested_goals.is_empty() {
|
||||
@ -256,7 +275,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
// instead of taking them. This would cause an ICE here, since we have
|
||||
// assertions against dropping an `InferCtxt` without taking opaques.
|
||||
// FIXME: Once we remove support for the old impl we can remove this.
|
||||
let _ = infcx.take_opaque_types();
|
||||
// FIXME: Could we make `build_with_canonical` into `enter_with_canonical` and call this at the end?
|
||||
infcx.reset_opaque_types();
|
||||
|
||||
result
|
||||
}
|
||||
@ -268,15 +288,15 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
/// logic of the solver.
|
||||
///
|
||||
/// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal]
|
||||
/// if you're inside of the solver or [InferCtxtEvalExt::evaluate_root_goal] if you're
|
||||
/// if you're inside of the solver or [SolverDelegateEvalExt::evaluate_root_goal] if you're
|
||||
/// outside of it.
|
||||
#[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)]
|
||||
fn evaluate_canonical_goal(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
|
||||
canonical_input: CanonicalInput<'tcx>,
|
||||
goal_evaluation: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
tcx: I,
|
||||
search_graph: &'a mut search_graph::SearchGraph<I>,
|
||||
canonical_input: CanonicalInput<I>,
|
||||
goal_evaluation: &mut ProofTreeBuilder<Infcx>,
|
||||
) -> QueryResult<I> {
|
||||
let mut canonical_goal_evaluation =
|
||||
goal_evaluation.new_canonical_goal_evaluation(canonical_input);
|
||||
|
||||
@ -315,7 +335,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
&mut self,
|
||||
goal_evaluation_kind: GoalEvaluationKind,
|
||||
source: GoalSource,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
) -> Result<(bool, Certainty), NoSolution> {
|
||||
let (normalization_nested_goals, has_changed, certainty) =
|
||||
self.evaluate_goal_raw(goal_evaluation_kind, source, goal)?;
|
||||
@ -336,8 +356,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
&mut self,
|
||||
goal_evaluation_kind: GoalEvaluationKind,
|
||||
_source: GoalSource,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
) -> Result<(NestedNormalizationGoals<TyCtxt<'tcx>>, bool, Certainty), NoSolution> {
|
||||
goal: Goal<I, I::Predicate>,
|
||||
) -> Result<(NestedNormalizationGoals<I>, bool, Certainty), NoSolution> {
|
||||
let (orig_values, canonical_goal) = self.canonicalize_goal(goal);
|
||||
let mut goal_evaluation =
|
||||
self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind);
|
||||
@ -377,10 +397,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
|
||||
fn instantiate_response_discarding_overflow(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
original_values: Vec<ty::GenericArg<'tcx>>,
|
||||
response: CanonicalResponse<'tcx>,
|
||||
) -> (NestedNormalizationGoals<TyCtxt<'tcx>>, Certainty, bool) {
|
||||
param_env: I::ParamEnv,
|
||||
original_values: Vec<I::GenericArg>,
|
||||
response: CanonicalResponse<I>,
|
||||
) -> (NestedNormalizationGoals<I>, Certainty, bool) {
|
||||
if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty {
|
||||
return (NestedNormalizationGoals::empty(), response.value.certainty, false);
|
||||
}
|
||||
@ -393,7 +413,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
(normalization_nested_goals, certainty, has_changed)
|
||||
}
|
||||
|
||||
fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult<'tcx> {
|
||||
fn compute_goal(&mut self, goal: Goal<I, I::Predicate>) -> QueryResult<I> {
|
||||
let Goal { param_env, predicate } = goal;
|
||||
let kind = predicate.kind();
|
||||
if let Some(kind) = kind.no_bound_vars() {
|
||||
@ -429,7 +449,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
|
||||
}
|
||||
ty::PredicateKind::ConstEquate(_, _) => {
|
||||
bug!("ConstEquate should not be emitted when `-Znext-solver` is active")
|
||||
panic!("ConstEquate should not be emitted when `-Znext-solver` is active")
|
||||
}
|
||||
ty::PredicateKind::NormalizesTo(predicate) => {
|
||||
self.compute_normalizes_to_goal(Goal { param_env, predicate })
|
||||
@ -565,21 +585,16 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
/// Record impl args in the proof tree for later access by `InspectCandidate`.
|
||||
pub(crate) fn record_impl_args(&mut self, impl_args: ty::GenericArgsRef<'tcx>) {
|
||||
pub(crate) fn record_impl_args(&mut self, impl_args: I::GenericArgs) {
|
||||
self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
pub(super) fn interner(&self) -> I {
|
||||
self.infcx.interner()
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(super) fn add_normalizes_to_goal(
|
||||
&mut self,
|
||||
mut goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
|
||||
) {
|
||||
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
|
||||
goal.predicate = goal
|
||||
.predicate
|
||||
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
|
||||
@ -588,11 +603,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
pub(super) fn add_goal(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
mut goal: ir::solve::Goal<I, I::Predicate>,
|
||||
) {
|
||||
pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
|
||||
goal.predicate = goal
|
||||
.predicate
|
||||
.fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env });
|
||||
@ -604,7 +615,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
pub(super) fn add_goals(
|
||||
&mut self,
|
||||
source: GoalSource,
|
||||
goals: impl IntoIterator<Item = ir::solve::Goal<I, I::Predicate>>,
|
||||
goals: impl IntoIterator<Item = Goal<I, I::Predicate>>,
|
||||
) {
|
||||
for goal in goals {
|
||||
self.add_goal(source, goal);
|
||||
@ -627,8 +638,8 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
/// If `kind` is an integer inference variable this will still return a ty infer var.
|
||||
pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term {
|
||||
match kind.kind() {
|
||||
ir::TermKind::Ty(_) => self.next_ty_infer().into(),
|
||||
ir::TermKind::Const(_) => self.next_const_infer().into(),
|
||||
ty::TermKind::Ty(_) => self.next_ty_infer().into(),
|
||||
ty::TermKind::Const(_) => self.next_const_infer().into(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,20 +648,17 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
/// This is the case if the `term` does not occur in any other part of the predicate
|
||||
/// and is able to name all other placeholder and inference variables.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
pub(super) fn term_is_fully_unconstrained(
|
||||
&self,
|
||||
goal: ir::solve::Goal<I, ir::NormalizesTo<I>>,
|
||||
) -> bool {
|
||||
pub(super) fn term_is_fully_unconstrained(&self, goal: Goal<I, ty::NormalizesTo<I>>) -> bool {
|
||||
let universe_of_term = match goal.predicate.term.kind() {
|
||||
ir::TermKind::Ty(ty) => {
|
||||
if let ir::Infer(ir::TyVar(vid)) = ty.kind() {
|
||||
ty::TermKind::Ty(ty) => {
|
||||
if let ty::Infer(ty::TyVar(vid)) = ty.kind() {
|
||||
self.infcx.universe_of_ty(vid).unwrap()
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ir::TermKind::Const(ct) => {
|
||||
if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() {
|
||||
ty::TermKind::Const(ct) => {
|
||||
if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() {
|
||||
self.infcx.universe_of_ct(vid).unwrap()
|
||||
} else {
|
||||
return false;
|
||||
@ -658,14 +666,14 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
}
|
||||
};
|
||||
|
||||
struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> {
|
||||
struct ContainsTermOrNotNameable<'a, Infcx: SolverDelegate<Interner = I>, I: Interner> {
|
||||
term: I::Term,
|
||||
universe_of_term: ir::UniverseIndex,
|
||||
universe_of_term: ty::UniverseIndex,
|
||||
infcx: &'a Infcx,
|
||||
}
|
||||
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> {
|
||||
fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> {
|
||||
impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> {
|
||||
fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> {
|
||||
if self.universe_of_term.can_name(universe) {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
@ -674,15 +682,15 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeVisitor<I>
|
||||
impl<Infcx: SolverDelegate<Interner = I>, I: Interner> TypeVisitor<I>
|
||||
for ContainsTermOrNotNameable<'_, Infcx, I>
|
||||
{
|
||||
type Result = ControlFlow<()>;
|
||||
fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
|
||||
match t.kind() {
|
||||
ir::Infer(ir::TyVar(vid)) => {
|
||||
if let ir::TermKind::Ty(term) = self.term.kind()
|
||||
&& let ir::Infer(ir::TyVar(term_vid)) = term.kind()
|
||||
ty::Infer(ty::TyVar(vid)) => {
|
||||
if let ty::TermKind::Ty(term) = self.term.kind()
|
||||
&& let ty::Infer(ty::TyVar(term_vid)) = term.kind()
|
||||
&& self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid)
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
@ -690,7 +698,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
self.check_nameable(self.infcx.universe_of_ty(vid).unwrap())
|
||||
}
|
||||
}
|
||||
ir::Placeholder(p) => self.check_nameable(p.universe()),
|
||||
ty::Placeholder(p) => self.check_nameable(p.universe()),
|
||||
_ => {
|
||||
if t.has_non_region_infer() || t.has_placeholders() {
|
||||
t.super_visit_with(self)
|
||||
@ -703,9 +711,9 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
|
||||
fn visit_const(&mut self, c: I::Const) -> Self::Result {
|
||||
match c.kind() {
|
||||
ir::ConstKind::Infer(ir::InferConst::Var(vid)) => {
|
||||
if let ir::TermKind::Const(term) = self.term.kind()
|
||||
&& let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = term.kind()
|
||||
ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
|
||||
if let ty::TermKind::Const(term) = self.term.kind()
|
||||
&& let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind()
|
||||
&& self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid)
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
@ -713,7 +721,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
self.check_nameable(self.infcx.universe_of_ct(vid).unwrap())
|
||||
}
|
||||
}
|
||||
ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
|
||||
ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe()),
|
||||
_ => {
|
||||
if c.has_non_region_infer() || c.has_placeholders() {
|
||||
c.super_visit_with(self)
|
||||
@ -741,7 +749,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.relate(param_env, lhs, ir::Variance::Invariant, rhs)
|
||||
self.relate(param_env, lhs, ty::Variance::Invariant, rhs)
|
||||
}
|
||||
|
||||
/// This should be used when relating a rigid alias with another type.
|
||||
@ -753,8 +761,8 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
pub(super) fn relate_rigid_alias_non_alias(
|
||||
&mut self,
|
||||
param_env: I::ParamEnv,
|
||||
alias: ir::AliasTerm<I>,
|
||||
variance: ir::Variance,
|
||||
alias: ty::AliasTerm<I>,
|
||||
variance: ty::Variance,
|
||||
term: I::Term,
|
||||
) -> Result<(), NoSolution> {
|
||||
// NOTE: this check is purely an optimization, the structural eq would
|
||||
@ -770,7 +778,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
// Alternatively we could modify `Equate` for this case by adding another
|
||||
// variant to `StructurallyRelateAliases`.
|
||||
let identity_args = self.fresh_args_for_item(alias.def_id);
|
||||
let rigid_ctor = ir::AliasTerm::new(tcx, alias.def_id, identity_args);
|
||||
let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args);
|
||||
let ctor_term = rigid_ctor.to_term(tcx);
|
||||
let obligations =
|
||||
self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?;
|
||||
@ -803,7 +811,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
sub: T,
|
||||
sup: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.relate(param_env, sub, ir::Variance::Covariant, sup)
|
||||
self.relate(param_env, sub, ty::Variance::Covariant, sup)
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
@ -811,7 +819,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
&mut self,
|
||||
param_env: I::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ir::Variance,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<(), NoSolution> {
|
||||
let goals = self.infcx.relate(param_env, lhs, variance, rhs)?;
|
||||
@ -830,20 +838,20 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
param_env: I::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<ir::solve::Goal<I, I::Predicate>>, NoSolution> {
|
||||
self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs)
|
||||
) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
|
||||
self.infcx.relate(param_env, lhs, ty::Variance::Invariant, rhs)
|
||||
}
|
||||
|
||||
pub(super) fn instantiate_binder_with_infer<T: TypeFoldable<I> + Copy>(
|
||||
&self,
|
||||
value: ir::Binder<I, T>,
|
||||
value: ty::Binder<I, T>,
|
||||
) -> T {
|
||||
self.infcx.instantiate_binder_with_infer(value)
|
||||
}
|
||||
|
||||
pub(super) fn enter_forall<T: TypeFoldable<I> + Copy, U>(
|
||||
&self,
|
||||
value: ir::Binder<I, T>,
|
||||
value: ty::Binder<I, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.infcx.enter_forall(value, f)
|
||||
@ -863,89 +871,72 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> {
|
||||
}
|
||||
args
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) {
|
||||
self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy());
|
||||
pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) {
|
||||
self.infcx.register_ty_outlives(ty, lt);
|
||||
}
|
||||
|
||||
pub(super) fn register_region_outlives(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) {
|
||||
pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) {
|
||||
// `b : a` ==> `a <= b`
|
||||
// (inlined from `InferCtxt::region_outlives_predicate`)
|
||||
self.infcx.sub_regions(
|
||||
rustc_infer::infer::SubregionOrigin::RelateRegionParamBound(DUMMY_SP),
|
||||
b,
|
||||
a,
|
||||
);
|
||||
self.infcx.sub_regions(b, a);
|
||||
}
|
||||
|
||||
/// Computes the list of goals required for `arg` to be well-formed
|
||||
pub(super) fn well_formed_goals(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
arg: ty::GenericArg<'tcx>,
|
||||
) -> Option<impl Iterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>> {
|
||||
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
|
||||
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
|
||||
}
|
||||
|
||||
pub(super) fn is_transmutable(
|
||||
&self,
|
||||
src_and_dst: rustc_transmute::Types<'tcx>,
|
||||
assume: rustc_transmute::Assume,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
use rustc_transmute::Answer;
|
||||
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
|
||||
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
||||
ObligationCause::dummy(),
|
||||
src_and_dst,
|
||||
assume,
|
||||
) {
|
||||
Answer::Yes => Ok(Certainty::Yes),
|
||||
Answer::No(_) | Answer::If(_) => Err(NoSolution),
|
||||
}
|
||||
param_env: I::ParamEnv,
|
||||
arg: I::GenericArg,
|
||||
) -> Option<Vec<Goal<I, I::Predicate>>> {
|
||||
self.infcx.well_formed_goals(param_env, arg)
|
||||
}
|
||||
|
||||
pub(super) fn trait_ref_is_knowable(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
param_env: I::ParamEnv,
|
||||
trait_ref: ty::TraitRef<I>,
|
||||
) -> Result<bool, NoSolution> {
|
||||
let infcx = self.infcx;
|
||||
let lazily_normalize_ty = |ty| self.structurally_normalize_ty(param_env, ty);
|
||||
coherence::trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty)
|
||||
.map(|is_knowable| is_knowable.is_ok())
|
||||
infcx.trait_ref_is_knowable(trait_ref, lazily_normalize_ty)
|
||||
}
|
||||
|
||||
pub(super) fn can_define_opaque_ty(&self, def_id: impl Into<DefId>) -> bool {
|
||||
self.infcx.can_define_opaque_ty(def_id)
|
||||
pub(super) fn fetch_eligible_assoc_item(
|
||||
&self,
|
||||
param_env: I::ParamEnv,
|
||||
goal_trait_ref: ty::TraitRef<I>,
|
||||
trait_assoc_def_id: I::DefId,
|
||||
impl_def_id: I::DefId,
|
||||
) -> Result<Option<I::DefId>, NoSolution> {
|
||||
self.infcx.fetch_eligible_assoc_item(
|
||||
param_env,
|
||||
goal_trait_ref,
|
||||
trait_assoc_def_id,
|
||||
impl_def_id,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool {
|
||||
self.infcx.defining_opaque_types().contains(&def_id)
|
||||
}
|
||||
|
||||
pub(super) fn insert_hidden_type(
|
||||
&mut self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
opaque_type_key: ty::OpaqueTypeKey<I>,
|
||||
param_env: I::ParamEnv,
|
||||
hidden_ty: I::Ty,
|
||||
) -> Result<(), NoSolution> {
|
||||
let mut goals = Vec::new();
|
||||
self.infcx.insert_hidden_type(
|
||||
opaque_type_key,
|
||||
DUMMY_SP,
|
||||
param_env,
|
||||
hidden_ty,
|
||||
&mut goals,
|
||||
)?;
|
||||
self.infcx.insert_hidden_type(opaque_type_key, param_env, hidden_ty, &mut goals)?;
|
||||
self.add_goals(GoalSource::Misc, goals);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn add_item_bounds_for_hidden_type(
|
||||
&mut self,
|
||||
opaque_def_id: DefId,
|
||||
opaque_args: ty::GenericArgsRef<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
opaque_def_id: I::DefId,
|
||||
opaque_args: I::GenericArgs,
|
||||
param_env: I::ParamEnv,
|
||||
hidden_ty: I::Ty,
|
||||
) {
|
||||
let mut goals = Vec::new();
|
||||
self.infcx.add_item_bounds_for_hidden_type(
|
||||
@ -962,10 +953,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// current inference context.
|
||||
pub(super) fn unify_existing_opaque_tys(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
key: ty::OpaqueTypeKey<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Vec<CanonicalResponse<'tcx>> {
|
||||
param_env: I::ParamEnv,
|
||||
key: ty::OpaqueTypeKey<I>,
|
||||
ty: I::Ty,
|
||||
) -> Vec<CanonicalResponse<I>> {
|
||||
// FIXME: Super inefficient to be cloning this...
|
||||
let opaques = self.infcx.clone_opaque_types_for_query_response();
|
||||
|
||||
@ -984,7 +975,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
ecx.eq(param_env, candidate_ty, ty)?;
|
||||
ecx.add_item_bounds_for_hidden_type(
|
||||
candidate_key.def_id.to_def_id(),
|
||||
candidate_key.def_id.into(),
|
||||
candidate_key.args,
|
||||
param_env,
|
||||
candidate_ty,
|
||||
@ -1001,23 +992,20 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// as an ambiguity rather than no-solution.
|
||||
pub(super) fn try_const_eval_resolve(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
unevaluated: ty::UnevaluatedConst<'tcx>,
|
||||
) -> Option<ty::Const<'tcx>> {
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
|
||||
Ok(Some(val)) => Some(ty::Const::new_value(
|
||||
self.interner(),
|
||||
val,
|
||||
self.interner()
|
||||
.type_of(unevaluated.def)
|
||||
.instantiate(self.interner(), unevaluated.args),
|
||||
)),
|
||||
Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None,
|
||||
Err(ErrorHandled::Reported(e, _)) => {
|
||||
Some(ty::Const::new_error(self.interner(), e.into()))
|
||||
}
|
||||
}
|
||||
param_env: I::ParamEnv,
|
||||
unevaluated: ty::UnevaluatedConst<I>,
|
||||
) -> Option<I::Const> {
|
||||
self.infcx.try_const_eval_resolve(param_env, unevaluated)
|
||||
}
|
||||
|
||||
pub(super) fn is_transmutable(
|
||||
&mut self,
|
||||
param_env: I::ParamEnv,
|
||||
dst: I::Ty,
|
||||
src: I::Ty,
|
||||
assume: I::Const,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
self.infcx.is_transmutable(param_env, dst, src, assume)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1030,7 +1018,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs.
|
||||
struct ReplaceAliasWithInfer<'me, 'a, Infcx, I>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
ecx: &'me mut EvalCtxt<'a, Infcx>,
|
||||
@ -1039,7 +1027,7 @@ where
|
||||
|
||||
impl<Infcx, I> TypeFolder<I> for ReplaceAliasWithInfer<'_, '_, Infcx, I>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
fn interner(&self) -> I {
|
||||
@ -1048,16 +1036,16 @@ where
|
||||
|
||||
fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
|
||||
match ty.kind() {
|
||||
ir::Alias(..) if !ty.has_escaping_bound_vars() => {
|
||||
ty::Alias(..) if !ty.has_escaping_bound_vars() => {
|
||||
let infer_ty = self.ecx.next_ty_infer();
|
||||
let normalizes_to = ir::PredicateKind::AliasRelate(
|
||||
let normalizes_to = ty::PredicateKind::AliasRelate(
|
||||
ty.into(),
|
||||
infer_ty.into(),
|
||||
AliasRelationDirection::Equate,
|
||||
ty::AliasRelationDirection::Equate,
|
||||
);
|
||||
self.ecx.add_goal(
|
||||
GoalSource::Misc,
|
||||
ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
);
|
||||
infer_ty
|
||||
}
|
||||
@ -1067,16 +1055,16 @@ where
|
||||
|
||||
fn fold_const(&mut self, ct: I::Const) -> I::Const {
|
||||
match ct.kind() {
|
||||
ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
|
||||
ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => {
|
||||
let infer_ct = self.ecx.next_const_infer();
|
||||
let normalizes_to = ir::PredicateKind::AliasRelate(
|
||||
let normalizes_to = ty::PredicateKind::AliasRelate(
|
||||
ct.into(),
|
||||
infer_ct.into(),
|
||||
AliasRelationDirection::Equate,
|
||||
ty::AliasRelationDirection::Equate,
|
||||
);
|
||||
self.ecx.add_goal(
|
||||
GoalSource::Misc,
|
||||
ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
Goal::new(self.interner(), self.param_env, normalizes_to),
|
||||
);
|
||||
infer_ct
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
use crate::solve::assembly::Candidate;
|
||||
|
||||
use super::EvalCtxt;
|
||||
use rustc_next_trait_solver::solve::{
|
||||
inspect, BuiltinImplSource, CandidateSource, NoSolution, QueryResult,
|
||||
};
|
||||
use rustc_type_ir::{InferCtxtLike, Interner};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rustc_type_ir::Interner;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::assembly::Candidate;
|
||||
use crate::solve::inspect;
|
||||
use crate::solve::{BuiltinImplSource, CandidateSource, EvalCtxt, NoSolution, QueryResult};
|
||||
|
||||
pub(in crate::solve) struct ProbeCtxt<'me, 'a, Infcx, I, F, T>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
ecx: &'me mut EvalCtxt<'a, Infcx, I>,
|
||||
@ -20,7 +21,7 @@ where
|
||||
impl<Infcx, I, F, T> ProbeCtxt<'_, '_, Infcx, I, F, T>
|
||||
where
|
||||
F: FnOnce(&T) -> inspect::ProbeKind<I>,
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> T) -> T {
|
||||
@ -56,7 +57,7 @@ where
|
||||
|
||||
pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, Infcx, I, F>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
cx: ProbeCtxt<'me, 'a, Infcx, I, F, QueryResult<I>>,
|
||||
@ -65,7 +66,7 @@ where
|
||||
|
||||
impl<Infcx, I, F> TraitProbeCtxt<'_, '_, Infcx, I, F>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
F: FnOnce(&QueryResult<I>) -> inspect::ProbeKind<I>,
|
||||
{
|
||||
@ -80,7 +81,7 @@ where
|
||||
|
||||
impl<'a, Infcx, I> EvalCtxt<'a, Infcx, I>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
/// `probe_kind` is only called when proof tree building is enabled so it can be
|
@ -3,16 +3,19 @@
|
||||
//! This code is *a bit* of a mess and can hopefully be
|
||||
//! mostly ignored. For a general overview of how it works,
|
||||
//! see the comment on [ProofTreeBuilder].
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::eval_ctxt::canonical;
|
||||
use crate::solve::{self, inspect, GenerateProofTree};
|
||||
use rustc_middle::bug;
|
||||
use rustc_next_trait_solver::solve::{
|
||||
CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult,
|
||||
use crate::solve::inspect;
|
||||
use crate::solve::{
|
||||
CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource, QueryInput,
|
||||
QueryResult,
|
||||
};
|
||||
use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
|
||||
/// The core data structure when building proof trees.
|
||||
///
|
||||
@ -34,9 +37,9 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
|
||||
/// trees. At the end of trait solving `ProofTreeBuilder::finalize`
|
||||
/// is called to recursively convert the whole structure to a
|
||||
/// finished proof tree.
|
||||
pub(in crate::solve) struct ProofTreeBuilder<Infcx, I = <Infcx as InferCtxtLike>::Interner>
|
||||
pub(in crate::solve) struct ProofTreeBuilder<Infcx, I = <Infcx as SolverDelegate>::Interner>
|
||||
where
|
||||
Infcx: InferCtxtLike<Interner = I>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
_infcx: PhantomData<Infcx>,
|
||||
@ -170,7 +173,7 @@ impl<I: Interner> WipCanonicalGoalEvaluationStep<I> {
|
||||
for _ in 0..self.probe_depth {
|
||||
match current.steps.last_mut() {
|
||||
Some(WipProbeStep::NestedProbe(p)) => current = p,
|
||||
_ => bug!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
current
|
||||
@ -232,7 +235,7 @@ impl<I: Interner> WipProbeStep<I> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
impl<Infcx: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
fn new(state: impl Into<DebugSolver<I>>) -> ProofTreeBuilder<Infcx> {
|
||||
ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData }
|
||||
}
|
||||
@ -293,15 +296,15 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
&mut self,
|
||||
goal: Goal<I, I::Predicate>,
|
||||
orig_values: &[I::GenericArg],
|
||||
kind: solve::GoalEvaluationKind,
|
||||
kind: GoalEvaluationKind,
|
||||
) -> ProofTreeBuilder<Infcx> {
|
||||
self.opt_nested(|| match kind {
|
||||
solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation {
|
||||
GoalEvaluationKind::Root => Some(WipGoalEvaluation {
|
||||
uncanonicalized_goal: goal,
|
||||
orig_values: orig_values.to_vec(),
|
||||
evaluation: None,
|
||||
}),
|
||||
solve::GoalEvaluationKind::Nested => None,
|
||||
GoalEvaluationKind::Nested => None,
|
||||
})
|
||||
}
|
||||
|
||||
@ -413,7 +416,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
|
||||
state.var_values.push(arg.into());
|
||||
}
|
||||
Some(s) => bug!("tried to add var values to {s:?}"),
|
||||
Some(s) => panic!("tried to add var values to {s:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,7 +433,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
}));
|
||||
state.probe_depth += 1;
|
||||
}
|
||||
Some(s) => bug!("tried to start probe to {s:?}"),
|
||||
Some(s) => panic!("tried to start probe to {s:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,7 +444,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
let prev = state.current_evaluation_scope().kind.replace(probe_kind);
|
||||
assert_eq!(prev, None);
|
||||
}
|
||||
_ => bug!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,7 +461,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
let prev = state.current_evaluation_scope().final_state.replace(final_state);
|
||||
assert_eq!(prev, None);
|
||||
}
|
||||
_ => bug!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -494,7 +497,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
);
|
||||
state.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal))
|
||||
}
|
||||
_ => bug!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,7 +521,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
.push(WipProbeStep::RecordImplArgs { impl_args });
|
||||
}
|
||||
None => {}
|
||||
_ => bug!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,7 +534,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
.push(WipProbeStep::MakeCanonicalResponse { shallow_certainty });
|
||||
}
|
||||
None => {}
|
||||
_ => bug!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,7 +547,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> {
|
||||
state.var_values.truncate(num_var_values);
|
||||
state.probe_depth -= 1;
|
||||
}
|
||||
_ => bug!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
|
||||
self
|
@ -0,0 +1,6 @@
|
||||
pub use rustc_type_ir::solve::inspect::*;
|
||||
|
||||
mod build;
|
||||
pub(in crate::solve) use build::*;
|
||||
|
||||
pub use crate::solve::eval_ctxt::canonical::instantiate_canonical_state;
|
@ -13,38 +13,23 @@
|
||||
//!
|
||||
//! FIXME(@lcnr): Write that section. If you read this before then ask me
|
||||
//! about it on zulip.
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::infer::canonical::CanonicalVarInfos;
|
||||
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,
|
||||
};
|
||||
|
||||
mod alias_relate;
|
||||
mod assembly;
|
||||
mod eval_ctxt;
|
||||
mod fulfill;
|
||||
pub mod inspect;
|
||||
mod normalize;
|
||||
mod normalizes_to;
|
||||
mod project_goals;
|
||||
mod search_graph;
|
||||
mod select;
|
||||
mod trait_goals;
|
||||
|
||||
pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt};
|
||||
pub use fulfill::{FulfillmentCtxt, NextSolverError};
|
||||
pub(crate) use normalize::deeply_normalize_for_diagnostics;
|
||||
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
|
||||
pub use select::InferCtxtSelectExt;
|
||||
use rustc_type_ir::inherent::*;
|
||||
pub use rustc_type_ir::solve::*;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
use tracing::instrument;
|
||||
|
||||
pub use self::eval_ctxt::{EvalCtxt, GenerateProofTree, SolverDelegateEvalExt};
|
||||
use crate::infcx::SolverDelegate;
|
||||
|
||||
/// How many fixpoint iterations we should attempt inside of the solver before bailing
|
||||
/// with overflow.
|
||||
@ -57,40 +42,30 @@ pub use select::InferCtxtSelectExt;
|
||||
/// recursion limit again. However, this feels very unlikely.
|
||||
const FIXPOINT_STEP_LIMIT: usize = 8;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum SolverMode {
|
||||
/// Ordinary trait solving, using everywhere except for coherence.
|
||||
Normal,
|
||||
/// Trait solving during coherence. There are a few notable differences
|
||||
/// between coherence and ordinary trait solving.
|
||||
///
|
||||
/// Most importantly, trait solving during coherence must not be incomplete,
|
||||
/// i.e. return `Err(NoSolution)` for goals for which a solution exists.
|
||||
/// This means that we must not make any guesses or arbitrary choices.
|
||||
Coherence,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
enum GoalEvaluationKind {
|
||||
Root,
|
||||
Nested,
|
||||
}
|
||||
|
||||
#[extension(trait CanonicalResponseExt)]
|
||||
impl<'tcx> Canonical<'tcx, Response<TyCtxt<'tcx>>> {
|
||||
fn has_no_inference_or_external_constraints(&self) -> bool {
|
||||
self.value.external_constraints.region_constraints.is_empty()
|
||||
&& self.value.var_values.is_identity()
|
||||
&& self.value.external_constraints.opaque_types.is_empty()
|
||||
}
|
||||
fn has_no_inference_or_external_constraints<I: Interner>(
|
||||
response: ty::Canonical<I, Response<I>>,
|
||||
) -> bool {
|
||||
response.value.external_constraints.region_constraints.is_empty()
|
||||
&& response.value.var_values.is_identity()
|
||||
&& response.value.external_constraints.opaque_types.is_empty()
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
impl<'a, Infcx, I> EvalCtxt<'a, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn compute_type_outlives_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, ty::OutlivesPredicate<I, I::Ty>>,
|
||||
) -> QueryResult<I> {
|
||||
let ty::OutlivesPredicate(ty, lt) = goal.predicate;
|
||||
self.register_ty_outlives(ty, lt);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
@ -99,21 +74,18 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn compute_region_outlives_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, ty::OutlivesPredicate<I, I::Region>>,
|
||||
) -> QueryResult<I> {
|
||||
let ty::OutlivesPredicate(a, b) = goal.predicate;
|
||||
self.register_region_outlives(a, b);
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn compute_coerce_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, CoercePredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
fn compute_coerce_goal(&mut self, goal: Goal<I, ty::CoercePredicate<I>>) -> QueryResult<I> {
|
||||
self.compute_subtype_goal(Goal {
|
||||
param_env: goal.param_env,
|
||||
predicate: SubtypePredicate {
|
||||
predicate: ty::SubtypePredicate {
|
||||
a_is_expected: false,
|
||||
a: goal.predicate.a,
|
||||
b: goal.predicate.b,
|
||||
@ -122,10 +94,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn compute_subtype_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, SubtypePredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
fn compute_subtype_goal(&mut self, goal: Goal<I, ty::SubtypePredicate<I>>) -> QueryResult<I> {
|
||||
if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||
} else {
|
||||
@ -134,8 +103,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
|
||||
if self.interner().is_object_safe(trait_def_id) {
|
||||
fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult<I> {
|
||||
if self.interner().trait_is_object_safe(trait_def_id) {
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
@ -143,10 +112,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn compute_well_formed_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
fn compute_well_formed_goal(&mut self, goal: Goal<I, I::GenericArg>) -> QueryResult<I> {
|
||||
match self.well_formed_goals(goal.param_env, goal.predicate) {
|
||||
Some(goals) => {
|
||||
self.add_goals(GoalSource::Misc, goals);
|
||||
@ -159,8 +125,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn compute_const_evaluatable_goal(
|
||||
&mut self,
|
||||
Goal { param_env, predicate: ct }: Goal<'tcx, ty::Const<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
Goal { param_env, predicate: ct }: Goal<I, I::Const>,
|
||||
) -> QueryResult<I> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
// We never return `NoSolution` here as `try_const_eval_resolve` emits an
|
||||
@ -190,7 +156,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
// - `Bound` cannot exist as we don't have a binder around the self Type
|
||||
// - `Expr` is part of `feature(generic_const_exprs)` and is not implemented yet
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Expr(_) => {
|
||||
bug!("unexpect const kind: {:?}", ct)
|
||||
panic!("unexpect const kind: {:?}", ct)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,8 +164,8 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn compute_const_arg_has_type_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, (I::Const, I::Ty)>,
|
||||
) -> QueryResult<I> {
|
||||
let (ct, ty) = goal.predicate;
|
||||
|
||||
let ct_ty = match ct.kind() {
|
||||
@ -216,7 +182,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
|
||||
}
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
self.interner().type_of(uv.def).instantiate(self.interner(), uv.args)
|
||||
self.interner().type_of(uv.def).instantiate(self.interner(), &uv.args)
|
||||
}
|
||||
ty::ConstKind::Expr(_) => unimplemented!(
|
||||
"`feature(generic_const_exprs)` is not supported in the new trait solver"
|
||||
@ -224,10 +190,10 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
ty::ConstKind::Param(_) => {
|
||||
unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`")
|
||||
}
|
||||
ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct),
|
||||
ty::ConstKind::Bound(_, _) => panic!("escaping bound vars in {:?}", ct),
|
||||
ty::ConstKind::Value(ty, _) => ty,
|
||||
ty::ConstKind::Placeholder(placeholder) => {
|
||||
placeholder.find_const_ty_from_env(goal.param_env)
|
||||
self.interner().find_const_ty_from_env(goal.param_env, placeholder)
|
||||
}
|
||||
};
|
||||
|
||||
@ -236,15 +202,19 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
/// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`.
|
||||
///
|
||||
/// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn try_merge_responses(
|
||||
&mut self,
|
||||
responses: &[CanonicalResponse<'tcx>],
|
||||
) -> Option<CanonicalResponse<'tcx>> {
|
||||
responses: &[CanonicalResponse<I>],
|
||||
) -> Option<CanonicalResponse<I>> {
|
||||
if responses.is_empty() {
|
||||
return None;
|
||||
}
|
||||
@ -260,14 +230,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
.iter()
|
||||
.find(|response| {
|
||||
response.value.certainty == Certainty::Yes
|
||||
&& response.has_no_inference_or_external_constraints()
|
||||
&& has_no_inference_or_external_constraints(**response)
|
||||
})
|
||||
.copied()
|
||||
}
|
||||
|
||||
/// If we fail to merge responses we flounder and return overflow or ambiguity.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tcx> {
|
||||
fn flounder(&mut self, responses: &[CanonicalResponse<I>]) -> QueryResult<I> {
|
||||
if responses.is_empty() {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -277,7 +247,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
certainty.unify_with(response.value.certainty)
|
||||
})
|
||||
else {
|
||||
bug!("expected flounder response to be ambiguous")
|
||||
panic!("expected flounder response to be ambiguous")
|
||||
};
|
||||
|
||||
Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
|
||||
@ -291,9 +261,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
fn structurally_normalize_ty(
|
||||
&mut self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Result<Ty<'tcx>, NoSolution> {
|
||||
param_env: I::ParamEnv,
|
||||
ty: I::Ty,
|
||||
) -> Result<I::Ty, NoSolution> {
|
||||
if let ty::Alias(..) = ty.kind() {
|
||||
let normalized_ty = self.next_ty_infer();
|
||||
let alias_relate_goal = Goal::new(
|
||||
@ -302,7 +272,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
ty::PredicateKind::AliasRelate(
|
||||
ty.into(),
|
||||
normalized_ty.into(),
|
||||
AliasRelationDirection::Equate,
|
||||
ty::AliasRelationDirection::Equate,
|
||||
),
|
||||
);
|
||||
self.add_goal(GoalSource::Misc, alias_relate_goal);
|
||||
@ -314,17 +284,17 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
}
|
||||
|
||||
fn response_no_constraints_raw<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
max_universe: UniverseIndex,
|
||||
variables: CanonicalVarInfos<'tcx>,
|
||||
fn response_no_constraints_raw<I: Interner>(
|
||||
tcx: I,
|
||||
max_universe: ty::UniverseIndex,
|
||||
variables: I::CanonicalVars,
|
||||
certainty: Certainty,
|
||||
) -> CanonicalResponse<'tcx> {
|
||||
Canonical {
|
||||
) -> CanonicalResponse<I> {
|
||||
ty::Canonical {
|
||||
max_universe,
|
||||
variables,
|
||||
value: Response {
|
||||
var_values: CanonicalVarValues::make_identity(tcx, variables),
|
||||
var_values: ty::CanonicalVarValues::make_identity(tcx, variables),
|
||||
// FIXME: maybe we should store the "no response" version in tcx, like
|
||||
// we do for tcx.types and stuff.
|
||||
external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()),
|
@ -1,14 +1,19 @@
|
||||
use crate::solve::EvalCtxt;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
use tracing::instrument;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, QueryResult};
|
||||
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
pub(super) fn normalize_anon_const(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
if let Some(normalized_const) = self.try_const_eval_resolve(
|
||||
goal.param_env,
|
||||
ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args),
|
@ -4,17 +4,21 @@
|
||||
//! 1. instantiate generic parameters,
|
||||
//! 2. equate the self type, and
|
||||
//! 3. instantiate and register where clauses.
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
|
||||
use crate::solve::EvalCtxt;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult};
|
||||
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
pub(super) fn normalize_inherent_associated_type(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let tcx = self.interner();
|
||||
let inherent = goal.predicate.alias.expect_ty(tcx);
|
||||
|
||||
@ -25,7 +29,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
self.eq(
|
||||
goal.param_env,
|
||||
inherent.self_ty(),
|
||||
tcx.type_of(impl_def_id).instantiate(tcx, impl_args),
|
||||
tcx.type_of(impl_def_id).instantiate(tcx, &impl_args),
|
||||
)?;
|
||||
|
||||
// Equate IAT with the RHS of the project goal
|
||||
@ -40,12 +44,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
self.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(inherent.def_id)
|
||||
.instantiate(tcx, inherent_args)
|
||||
.into_iter()
|
||||
.map(|(pred, _)| goal.with(tcx, pred)),
|
||||
.iter_instantiated(tcx, &inherent_args)
|
||||
.map(|pred| goal.with(tcx, pred)),
|
||||
);
|
||||
|
||||
let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, inherent_args);
|
||||
let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, &inherent_args);
|
||||
self.instantiate_normalizes_to_term(goal, normalized.into());
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
@ -1,35 +1,33 @@
|
||||
use crate::traits::specialization_graph::{self, LeafDef, Node};
|
||||
|
||||
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
|
||||
use super::assembly::{self, structural_traits, Candidate};
|
||||
use super::{EvalCtxt, GoalSource};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::inspect::ProbeKind;
|
||||
use rustc_infer::traits::solve::MaybeCause;
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::BuiltinImplSource;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::NormalizesTo;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{TypeVisitableExt, Upcast};
|
||||
use rustc_span::{ErrorGuaranteed, DUMMY_SP};
|
||||
|
||||
mod anon_const;
|
||||
mod inherent;
|
||||
mod opaque_types;
|
||||
mod weak_types;
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'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 tracing::instrument;
|
||||
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
|
||||
use crate::solve::assembly::{self, Candidate};
|
||||
use crate::solve::inspect::ProbeKind;
|
||||
use crate::solve::{
|
||||
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
|
||||
NoSolution, QueryResult,
|
||||
};
|
||||
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
pub(super) fn compute_normalizes_to_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, NormalizesTo<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
self.set_is_normalizes_to_goal();
|
||||
debug_assert!(self.term_is_fully_unconstrained(goal));
|
||||
let normalize_result = self
|
||||
@ -49,10 +47,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// Normalize the given alias by at least one step. If the alias is rigid, this
|
||||
/// returns `NoSolution`.
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
fn normalize_at_least_one_step(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, NormalizesTo<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
fn normalize_at_least_one_step(&mut self, goal: Goal<I, NormalizesTo<I>>) -> QueryResult<I> {
|
||||
match goal.predicate.alias.kind(self.interner()) {
|
||||
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
|
||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||
@ -72,38 +67,42 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// emit nested `AliasRelate` goals to structurally normalize the alias.
|
||||
pub fn instantiate_normalizes_to_term(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, NormalizesTo<'tcx>>,
|
||||
term: ty::Term<'tcx>,
|
||||
goal: Goal<I, NormalizesTo<I>>,
|
||||
term: I::Term,
|
||||
) {
|
||||
self.eq(goal.param_env, goal.predicate.term, term)
|
||||
.expect("expected goal term to be fully unconstrained");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
fn self_ty(self) -> Ty<'tcx> {
|
||||
impl<Infcx, I> assembly::GoalKind<Infcx> for NormalizesTo<I>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
fn self_ty(self) -> I::Ty {
|
||||
self.self_ty()
|
||||
}
|
||||
|
||||
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
|
||||
fn trait_ref(self, tcx: I) -> ty::TraitRef<I> {
|
||||
self.alias.trait_ref(tcx)
|
||||
}
|
||||
|
||||
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||
fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self {
|
||||
self.with_self_ty(tcx, self_ty)
|
||||
}
|
||||
|
||||
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
|
||||
fn trait_def_id(self, tcx: I) -> I::DefId {
|
||||
self.trait_def_id(tcx)
|
||||
}
|
||||
|
||||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
source: CandidateSource<'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
source: CandidateSource<I>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if let Some(projection_pred) = assumption.as_projection_clause() {
|
||||
if projection_pred.projection_def_id() == goal.predicate.def_id() {
|
||||
let tcx = ecx.interner();
|
||||
@ -121,9 +120,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
// Add GAT where clauses from the trait's definition
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(goal.predicate.def_id())
|
||||
.instantiate_own(tcx, goal.predicate.alias.args)
|
||||
.map(|(pred, _)| goal.with(tcx, pred)),
|
||||
tcx.own_predicates_of(goal.predicate.def_id())
|
||||
.iter_instantiated(tcx, &goal.predicate.alias.args)
|
||||
.map(|pred| goal.with(tcx, pred)),
|
||||
);
|
||||
|
||||
then(ecx)
|
||||
@ -137,24 +136,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_impl_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, NormalizesTo<'tcx>>,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, NormalizesTo<I>>,
|
||||
impl_def_id: I::DefId,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let tcx = ecx.interner();
|
||||
|
||||
let goal_trait_ref = goal.predicate.alias.trait_ref(tcx);
|
||||
let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
if !drcx.args_may_unify(
|
||||
goal.predicate.trait_ref(tcx).args,
|
||||
impl_trait_header.trait_ref.skip_binder().args,
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
|
||||
if !ecx.interner().args_may_unify_deep(
|
||||
goal.predicate.alias.trait_ref(tcx).args,
|
||||
impl_trait_ref.skip_binder().args,
|
||||
) {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// We have to ignore negative impls when projecting.
|
||||
let impl_polarity = impl_trait_header.polarity;
|
||||
let impl_polarity = tcx.impl_polarity(impl_def_id);
|
||||
match impl_polarity {
|
||||
ty::ImplPolarity::Negative => return Err(NoSolution),
|
||||
ty::ImplPolarity::Reservation => {
|
||||
@ -165,30 +163,28 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
|
||||
let impl_args = ecx.fresh_args_for_item(impl_def_id);
|
||||
let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args);
|
||||
let impl_trait_ref = impl_trait_ref.instantiate(tcx, &impl_args);
|
||||
|
||||
ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?;
|
||||
|
||||
let where_clause_bounds = tcx
|
||||
.predicates_of(impl_def_id)
|
||||
.instantiate(tcx, impl_args)
|
||||
.predicates
|
||||
.into_iter()
|
||||
.iter_instantiated(tcx, &impl_args)
|
||||
.map(|pred| goal.with(tcx, pred));
|
||||
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
|
||||
|
||||
// Add GAT where clauses from the trait's definition
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(goal.predicate.def_id())
|
||||
.instantiate_own(tcx, goal.predicate.alias.args)
|
||||
.map(|(pred, _)| goal.with(tcx, pred)),
|
||||
tcx.own_predicates_of(goal.predicate.def_id())
|
||||
.iter_instantiated(tcx, &goal.predicate.alias.args)
|
||||
.map(|pred| goal.with(tcx, pred)),
|
||||
);
|
||||
|
||||
// In case the associated item is hidden due to specialization, we have to
|
||||
// return ambiguity this would otherwise be incomplete, resulting in
|
||||
// unsoundness during coherence (#105782).
|
||||
let Some(assoc_def) = ecx.fetch_eligible_assoc_item_def(
|
||||
let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item(
|
||||
goal.param_env,
|
||||
goal_trait_ref,
|
||||
goal.predicate.def_id(),
|
||||
@ -198,21 +194,23 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
||||
};
|
||||
|
||||
let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| {
|
||||
let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason);
|
||||
let error_response = |ecx: &mut EvalCtxt<'_, Infcx>, msg: &str| {
|
||||
let guar = tcx.delay_bug(msg);
|
||||
let error_term = match goal.predicate.alias.kind(tcx) {
|
||||
ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(),
|
||||
ty::AliasTermKind::ProjectionConst => ty::Const::new_error(tcx, guar).into(),
|
||||
kind => bug!("expected projection, found {kind:?}"),
|
||||
ty::AliasTermKind::ProjectionConst => Const::new_error(tcx, guar).into(),
|
||||
kind => panic!("expected projection, found {kind:?}"),
|
||||
};
|
||||
ecx.instantiate_normalizes_to_term(goal, error_term);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
};
|
||||
|
||||
if !assoc_def.item.defaultness(tcx).has_value() {
|
||||
return error_response(ecx, "missing value for assoc item in impl");
|
||||
if !tcx.has_item_definition(target_item_def_id) {
|
||||
return error_response(ecx, "missing item");
|
||||
}
|
||||
|
||||
let target_container_def_id = tcx.parent(target_item_def_id);
|
||||
|
||||
// Getting the right args here is complex, e.g. given:
|
||||
// - a goal `<Vec<u32> as Trait<i32>>::Assoc<u64>`
|
||||
// - the applicable impl `impl<T> Trait<i32> for Vec<T>`
|
||||
@ -223,39 +221,40 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
//
|
||||
// And then map these args to the args of the defining impl of `Assoc`, going
|
||||
// from `[u32, u64]` to `[u32, i32, u64]`.
|
||||
let associated_item_args =
|
||||
ecx.translate_args(&assoc_def, goal, impl_def_id, impl_args, impl_trait_ref)?;
|
||||
let target_args = ecx.translate_args(
|
||||
goal,
|
||||
impl_def_id,
|
||||
impl_args,
|
||||
impl_trait_ref,
|
||||
target_container_def_id,
|
||||
)?;
|
||||
|
||||
if !tcx.check_args_compatible(assoc_def.item.def_id, associated_item_args) {
|
||||
return error_response(
|
||||
ecx,
|
||||
"associated item has mismatched generic item arguments",
|
||||
);
|
||||
if !tcx.check_args_compatible(target_item_def_id, target_args) {
|
||||
return error_response(ecx, "associated item has mismatched arguments");
|
||||
}
|
||||
|
||||
// Finally we construct the actual value of the associated type.
|
||||
let term = match goal.predicate.alias.kind(tcx) {
|
||||
ty::AliasTermKind::ProjectionTy => {
|
||||
tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into())
|
||||
tcx.type_of(target_item_def_id).map_bound(|ty| ty.into())
|
||||
}
|
||||
ty::AliasTermKind::ProjectionConst => {
|
||||
if tcx.features().associated_const_equality {
|
||||
bug!("associated const projection is not supported yet")
|
||||
if tcx.features().associated_const_equality() {
|
||||
panic!("associated const projection is not supported yet")
|
||||
} else {
|
||||
ty::EarlyBinder::bind(
|
||||
ty::Const::new_error_with_message(
|
||||
Const::new_error_with_message(
|
||||
tcx,
|
||||
DUMMY_SP,
|
||||
"associated const projection is not supported yet",
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
kind => bug!("expected projection, found {kind:?}"),
|
||||
kind => panic!("expected projection, found {kind:?}"),
|
||||
};
|
||||
|
||||
ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args));
|
||||
ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, &target_args));
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
@ -263,63 +262,60 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
/// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error`
|
||||
/// and succeed. Can experiment with this to figure out what results in better error messages.
|
||||
fn consider_error_guaranteed_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
_guar: ErrorGuaranteed,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
_guar: I::ErrorGuaranteed,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
Err(NoSolution)
|
||||
}
|
||||
|
||||
fn consider_auto_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx.interner().dcx().span_delayed_bug(
|
||||
ecx.interner().def_span(goal.predicate.def_id()),
|
||||
"associated types not allowed on auto traits",
|
||||
);
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
_goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
ecx.interner().delay_bug("associated types not allowed on auto traits");
|
||||
Err(NoSolution)
|
||||
}
|
||||
|
||||
fn consider_trait_alias_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("trait aliases do not have associated types: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("trait aliases do not have associated types: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_sized_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("`Sized` does not have an associated type: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("`Sized` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_pointer_like_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("`PointerLike` does not have an associated type: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("`PointerLike` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_fn_ptr_trait_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("`FnPtr` does not have an associated type: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("`FnPtr` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let tcx = ecx.interner();
|
||||
let tupled_inputs_and_output =
|
||||
match structural_traits::extract_tupled_inputs_and_output_from_callable(
|
||||
@ -333,7 +329,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
};
|
||||
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
|
||||
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output])
|
||||
ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output])
|
||||
});
|
||||
|
||||
let pred = tupled_inputs_and_output
|
||||
@ -359,16 +355,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_async_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let tcx = ecx.interner();
|
||||
|
||||
let env_region = match goal_kind {
|
||||
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2),
|
||||
// Doesn't matter what this region is
|
||||
ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
|
||||
ty::ClosureKind::FnOnce => Region::new_static(tcx),
|
||||
};
|
||||
let (tupled_inputs_and_output_and_coroutine, nested_preds) =
|
||||
structural_traits::extract_tupled_inputs_and_output_from_async_callable(
|
||||
@ -379,7 +375,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
)?;
|
||||
let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
|
||||
|AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| {
|
||||
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output_ty])
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(TraitSolverLangItem::Sized),
|
||||
[output_ty],
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
@ -391,7 +391,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
coroutine_return_ty,
|
||||
}| {
|
||||
let (projection_term, term) = if tcx
|
||||
.is_lang_item(goal.predicate.def_id(), LangItem::CallOnceFuture)
|
||||
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallOnceFuture)
|
||||
{
|
||||
(
|
||||
ty::AliasTerm::new(
|
||||
@ -401,34 +401,41 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
),
|
||||
output_coroutine_ty.into(),
|
||||
)
|
||||
} else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CallRefFuture) {
|
||||
(
|
||||
ty::AliasTerm::new(
|
||||
tcx,
|
||||
goal.predicate.def_id(),
|
||||
[
|
||||
ty::GenericArg::from(goal.predicate.self_ty()),
|
||||
tupled_inputs_ty.into(),
|
||||
env_region.into(),
|
||||
],
|
||||
),
|
||||
output_coroutine_ty.into(),
|
||||
)
|
||||
} else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::AsyncFnOnceOutput)
|
||||
} else if tcx
|
||||
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallRefFuture)
|
||||
{
|
||||
(
|
||||
ty::AliasTerm::new(
|
||||
tcx,
|
||||
goal.predicate.def_id(),
|
||||
[
|
||||
ty::GenericArg::from(goal.predicate.self_ty()),
|
||||
I::GenericArg::from(goal.predicate.self_ty()),
|
||||
tupled_inputs_ty.into(),
|
||||
env_region.into(),
|
||||
],
|
||||
),
|
||||
output_coroutine_ty.into(),
|
||||
)
|
||||
} else if tcx.is_lang_item(
|
||||
goal.predicate.def_id(),
|
||||
TraitSolverLangItem::AsyncFnOnceOutput,
|
||||
) {
|
||||
(
|
||||
ty::AliasTerm::new(
|
||||
tcx,
|
||||
goal.predicate.def_id(),
|
||||
[
|
||||
I::GenericArg::from(goal.predicate.self_ty()),
|
||||
tupled_inputs_ty.into(),
|
||||
],
|
||||
),
|
||||
coroutine_return_ty.into(),
|
||||
)
|
||||
} else {
|
||||
bug!("no such associated type in `AsyncFn*`: {:?}", goal.predicate.def_id())
|
||||
panic!(
|
||||
"no such associated type in `AsyncFn*`: {:?}",
|
||||
goal.predicate.def_id()
|
||||
)
|
||||
};
|
||||
ty::ProjectionPredicate { projection_term, term }
|
||||
},
|
||||
@ -450,9 +457,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let [
|
||||
closure_fn_kind_ty,
|
||||
goal_kind_ty,
|
||||
@ -462,7 +469,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
coroutine_captures_by_ref_ty,
|
||||
] = **goal.predicate.alias.args
|
||||
else {
|
||||
bug!();
|
||||
panic!();
|
||||
};
|
||||
|
||||
// Bail if the upvars haven't been constrained.
|
||||
@ -497,18 +504,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_tuple_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("`Tuple` does not have an associated type: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("`Tuple` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let tcx = ecx.interner();
|
||||
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
|
||||
let metadata_def_id = tcx.require_lang_item(TraitSolverLangItem::Metadata);
|
||||
assert_eq!(metadata_def_id, goal.predicate.def_id());
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
let metadata_ty = match goal.predicate.self_ty().kind() {
|
||||
@ -530,16 +537,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Foreign(..)
|
||||
| ty::Dynamic(_, _, ty::DynStar) => tcx.types.unit,
|
||||
| ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(tcx),
|
||||
|
||||
ty::Error(e) => Ty::new_error(tcx, *e),
|
||||
ty::Error(e) => Ty::new_error(tcx, e),
|
||||
|
||||
ty::Str | ty::Slice(_) => tcx.types.usize,
|
||||
ty::Str | ty::Slice(_) => Ty::new_usize(tcx),
|
||||
|
||||
ty::Dynamic(_, _, ty::Dyn) => {
|
||||
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
|
||||
let dyn_metadata = tcx.require_lang_item(TraitSolverLangItem::DynMetadata);
|
||||
tcx.type_of(dyn_metadata)
|
||||
.instantiate(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
|
||||
.instantiate(tcx, &[I::GenericArg::from(goal.predicate.self_ty())])
|
||||
}
|
||||
|
||||
ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
|
||||
@ -549,32 +556,31 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
// exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
|
||||
let sized_predicate = ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::Sized, None),
|
||||
[ty::GenericArg::from(goal.predicate.self_ty())],
|
||||
tcx.require_lang_item(TraitSolverLangItem::Sized),
|
||||
[I::GenericArg::from(goal.predicate.self_ty())],
|
||||
);
|
||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||
ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate));
|
||||
tcx.types.unit
|
||||
Ty::new_unit(tcx)
|
||||
}
|
||||
|
||||
ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
|
||||
None => tcx.types.unit,
|
||||
Some(tail_def) => {
|
||||
let tail_ty = tail_def.ty(tcx, args);
|
||||
Ty::new_projection(tcx, metadata_def_id, [tail_ty])
|
||||
ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(tcx) {
|
||||
None => Ty::new_unit(tcx),
|
||||
Some(tail_ty) => {
|
||||
Ty::new_projection(tcx, metadata_def_id, [tail_ty.instantiate(tcx, &args)])
|
||||
}
|
||||
},
|
||||
ty::Adt(_, _) => tcx.types.unit,
|
||||
ty::Adt(_, _) => Ty::new_unit(tcx),
|
||||
|
||||
ty::Tuple(elements) => match elements.last() {
|
||||
None => tcx.types.unit,
|
||||
None => Ty::new_unit(tcx),
|
||||
Some(&tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]),
|
||||
},
|
||||
|
||||
ty::Infer(
|
||||
ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
|
||||
)
|
||||
| ty::Bound(..) => bug!(
|
||||
| ty::Bound(..) => panic!(
|
||||
"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
|
||||
goal.predicate.self_ty()
|
||||
),
|
||||
@ -586,11 +592,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_future_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
let ty::Coroutine(def_id, args) = self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -622,11 +628,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
let ty::Coroutine(def_id, args) = self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -658,18 +664,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_fused_iterator_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("`FusedIterator` does not have an associated type: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("`FusedIterator` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_async_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
let ty::Coroutine(def_id, args) = self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -685,10 +691,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
// coroutine yield ty `Poll<Option<I>>`.
|
||||
let wrapped_expected_ty = Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)),
|
||||
tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Poll)),
|
||||
tcx.mk_args(&[Ty::new_adt(
|
||||
tcx,
|
||||
tcx.adt_def(tcx.require_lang_item(LangItem::Option, None)),
|
||||
tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Option)),
|
||||
tcx.mk_args(&[expected_ty.into()]),
|
||||
)
|
||||
.into()]),
|
||||
@ -701,11 +707,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_coroutine_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
let ty::Coroutine(def_id, args) = self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -717,15 +723,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
let coroutine = args.as_coroutine();
|
||||
|
||||
let term = if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineReturn) {
|
||||
let term = if tcx
|
||||
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineReturn)
|
||||
{
|
||||
coroutine.return_ty().into()
|
||||
} else if tcx.is_lang_item(goal.predicate.def_id(), LangItem::CoroutineYield) {
|
||||
} else if tcx.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineYield) {
|
||||
coroutine.yield_ty().into()
|
||||
} else {
|
||||
bug!(
|
||||
"unexpected associated item `<{self_ty} as Coroutine>::{}`",
|
||||
tcx.item_name(goal.predicate.def_id())
|
||||
)
|
||||
panic!("unexpected associated item `{:?}` for `{self_ty:?}`", goal.predicate.def_id())
|
||||
};
|
||||
|
||||
Self::probe_and_consider_implied_clause(
|
||||
@ -748,18 +753,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_structural_builtin_unsize_candidates(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Vec<Candidate<TyCtxt<'tcx>>> {
|
||||
bug!("`Unsize` does not have an associated type: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Vec<Candidate<I>> {
|
||||
panic!("`Unsize` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_discriminant_kind_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let discriminant_ty = match *self_ty.kind() {
|
||||
let discriminant_ty = match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
@ -794,7 +799,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
|
||||
| ty::Bound(..) => bug!(
|
||||
| ty::Bound(..) => panic!(
|
||||
"unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`",
|
||||
goal.predicate.self_ty()
|
||||
),
|
||||
@ -807,11 +812,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_async_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let async_destructor_ty = match *self_ty.kind() {
|
||||
let async_destructor_ty = match self_ty.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(..)
|
||||
@ -842,12 +847,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
|
||||
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
|
||||
| ty::Foreign(..)
|
||||
| ty::Bound(..) => bug!(
|
||||
| ty::Bound(..) => panic!(
|
||||
"unexpected self ty `{:?}` when normalizing `<T as AsyncDestruct>::AsyncDestructor`",
|
||||
goal.predicate.self_ty()
|
||||
),
|
||||
|
||||
ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => bug!(
|
||||
ty::Pat(..) | ty::Dynamic(..) | ty::Coroutine(..) | ty::CoroutineWitness(..) => panic!(
|
||||
"`consider_builtin_async_destruct_candidate` is not yet implemented for type: {self_ty:?}"
|
||||
),
|
||||
};
|
||||
@ -860,93 +865,56 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_destruct_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("`Destruct` does not have an associated type: {:?}", goal);
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("`Destruct` does not have an associated type: {:?}", goal);
|
||||
}
|
||||
|
||||
fn consider_builtin_transmute_candidate(
|
||||
_ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
|
||||
_ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
fn translate_args(
|
||||
&mut self,
|
||||
assoc_def: &LeafDef,
|
||||
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
|
||||
impl_def_id: DefId,
|
||||
impl_args: ty::GenericArgsRef<'tcx>,
|
||||
impl_trait_ref: rustc_type_ir::TraitRef<TyCtxt<'tcx>>,
|
||||
) -> Result<ty::GenericArgsRef<'tcx>, NoSolution> {
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
impl_def_id: I::DefId,
|
||||
impl_args: I::GenericArgs,
|
||||
impl_trait_ref: rustc_type_ir::TraitRef<I>,
|
||||
target_container_def_id: I::DefId,
|
||||
) -> Result<I::GenericArgs, NoSolution> {
|
||||
let tcx = self.interner();
|
||||
Ok(match assoc_def.defining_node {
|
||||
Node::Trait(_) => goal.predicate.alias.args,
|
||||
Node::Impl(target_impl_def_id) => {
|
||||
if target_impl_def_id == impl_def_id {
|
||||
// Same impl, no need to fully translate, just a rebase from
|
||||
// the trait is sufficient.
|
||||
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args)
|
||||
} else {
|
||||
let target_args = self.fresh_args_for_item(target_impl_def_id);
|
||||
let target_trait_ref = tcx
|
||||
.impl_trait_ref(target_impl_def_id)
|
||||
.unwrap()
|
||||
.instantiate(tcx, target_args);
|
||||
// Relate source impl to target impl by equating trait refs.
|
||||
self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?;
|
||||
// Also add predicates since they may be needed to constrain the
|
||||
// target impl's params.
|
||||
self.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(target_impl_def_id)
|
||||
.instantiate(tcx, target_args)
|
||||
.into_iter()
|
||||
.map(|(pred, _)| goal.with(tcx, pred)),
|
||||
);
|
||||
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args)
|
||||
}
|
||||
}
|
||||
Ok(if target_container_def_id == impl_trait_ref.def_id {
|
||||
// Default value from the trait definition. No need to rebase.
|
||||
goal.predicate.alias.args
|
||||
} else if target_container_def_id == impl_def_id {
|
||||
// Same impl, no need to fully translate, just a rebase from
|
||||
// the trait is sufficient.
|
||||
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args)
|
||||
} else {
|
||||
let target_args = self.fresh_args_for_item(target_container_def_id);
|
||||
let target_trait_ref =
|
||||
tcx.impl_trait_ref(target_container_def_id).instantiate(tcx, &target_args);
|
||||
// Relate source impl to target impl by equating trait refs.
|
||||
self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?;
|
||||
// Also add predicates since they may be needed to constrain the
|
||||
// target impl's params.
|
||||
self.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(target_container_def_id)
|
||||
.iter_instantiated(tcx, &target_args)
|
||||
.map(|pred| goal.with(tcx, pred)),
|
||||
);
|
||||
goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args)
|
||||
})
|
||||
}
|
||||
|
||||
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
|
||||
///
|
||||
/// FIXME: We should merge these 3 implementations as it's likely that they otherwise
|
||||
/// diverge.
|
||||
#[instrument(level = "trace", skip(self, param_env), ret)]
|
||||
fn fetch_eligible_assoc_item_def(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
goal_trait_ref: ty::TraitRef<'tcx>,
|
||||
trait_assoc_def_id: DefId,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Option<LeafDef>, NoSolution> {
|
||||
let node_item =
|
||||
specialization_graph::assoc_def(self.interner(), impl_def_id, trait_assoc_def_id)
|
||||
.map_err(|ErrorGuaranteed { .. }| NoSolution)?;
|
||||
|
||||
let eligible = if node_item.is_final() {
|
||||
// Non-specializable items are always projectable.
|
||||
true
|
||||
} else {
|
||||
// Only reveal a specializable default if we're past type-checking
|
||||
// and the obligation is monomorphic, otherwise passes such as
|
||||
// transmute checking and polymorphic MIR optimizations could
|
||||
// get a result which isn't correct for all monomorphizations.
|
||||
if param_env.reveal() == Reveal::All {
|
||||
let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
|
||||
!poly_trait_ref.still_further_specializable()
|
||||
} else {
|
||||
trace!(?node_item.item.def_id, "not eligible due to default");
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
if eligible { Ok(Some(node_item)) } else { Ok(None) }
|
||||
}
|
||||
}
|
@ -1,20 +1,23 @@
|
||||
//! Computes a normalizes-to (projection) goal for opaque types. This goal
|
||||
//! behaves differently depending on the param-env's reveal mode and whether
|
||||
//! the opaque is in a defining scope.
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::Reveal;
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::util::NotUniqueParam;
|
||||
|
||||
use crate::solve::{EvalCtxt, SolverMode};
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode};
|
||||
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
pub(super) fn normalize_opaque_type(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let tcx = self.interner();
|
||||
let opaque_ty = goal.predicate.alias;
|
||||
let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const");
|
||||
@ -31,7 +34,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
// FIXME: This may have issues when the args contain aliases...
|
||||
match self.interner().uses_unique_placeholders_ignoring_regions(opaque_ty.args) {
|
||||
match uses_unique_placeholders_ignoring_regions(self.interner(), opaque_ty.args) {
|
||||
Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
|
||||
return self.evaluate_added_goals_and_make_canonical_response(
|
||||
Certainty::AMBIGUOUS,
|
||||
@ -60,6 +63,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
// Otherwise, define a new opaque type
|
||||
// FIXME: should we use `inject_hidden_type_unchecked` here?
|
||||
self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
|
||||
self.add_item_bounds_for_hidden_type(
|
||||
opaque_ty.def_id,
|
||||
@ -82,10 +86,51 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
}
|
||||
(Reveal::All, _) => {
|
||||
// FIXME: Add an assertion that opaque type storage is empty.
|
||||
let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args);
|
||||
let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, &opaque_ty.args);
|
||||
self.eq(goal.param_env, expected, actual)?;
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether each generic argument is simply a unique generic placeholder.
|
||||
///
|
||||
/// FIXME: Interner argument is needed to constrain the `I` parameter.
|
||||
pub fn uses_unique_placeholders_ignoring_regions<I: Interner>(
|
||||
_interner: I,
|
||||
args: I::GenericArgs,
|
||||
) -> Result<(), NotUniqueParam<I>> {
|
||||
let mut seen = GrowableBitSet::default();
|
||||
for arg in args {
|
||||
match arg.kind() {
|
||||
// Ignore regions, since we can't resolve those in a canonicalized
|
||||
// query in the trait solver.
|
||||
ty::GenericArgKind::Lifetime(_) => {}
|
||||
ty::GenericArgKind::Type(t) => match t.kind() {
|
||||
ty::Placeholder(p) => {
|
||||
if !seen.insert(p.var()) {
|
||||
return Err(NotUniqueParam::DuplicateParam(t.into()));
|
||||
}
|
||||
}
|
||||
_ => return Err(NotUniqueParam::NotParam(t.into())),
|
||||
},
|
||||
ty::GenericArgKind::Const(c) => match c.kind() {
|
||||
ty::ConstKind::Placeholder(p) => {
|
||||
if !seen.insert(p.var()) {
|
||||
return Err(NotUniqueParam::DuplicateParam(c.into()));
|
||||
}
|
||||
}
|
||||
_ => return Err(NotUniqueParam::NotParam(c.into())),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// FIXME: This should check for dupes and non-params first, then infer vars.
|
||||
pub enum NotUniqueParam<I: Interner> {
|
||||
DuplicateParam(I::GenericArg),
|
||||
NotParam(I::GenericArg),
|
||||
}
|
@ -3,17 +3,21 @@
|
||||
//!
|
||||
//! Since a weak alias is never ambiguous, this just computes the `type_of` of
|
||||
//! the alias and registers the where-clauses of the type alias.
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
|
||||
use rustc_middle::ty;
|
||||
|
||||
use crate::solve::EvalCtxt;
|
||||
use rustc_type_ir::{self as ty, Interner};
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult};
|
||||
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
pub(super) fn normalize_weak_type(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, ty::NormalizesTo<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let tcx = self.interner();
|
||||
let weak_ty = goal.predicate.alias;
|
||||
|
||||
@ -21,13 +25,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
self.add_goals(
|
||||
GoalSource::Misc,
|
||||
tcx.predicates_of(weak_ty.def_id)
|
||||
.instantiate(tcx, weak_ty.args)
|
||||
.predicates
|
||||
.into_iter()
|
||||
.iter_instantiated(tcx, &weak_ty.args)
|
||||
.map(|pred| goal.with(tcx, pred)),
|
||||
);
|
||||
|
||||
let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args);
|
||||
let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, &weak_ty.args);
|
||||
self.instantiate_normalizes_to_term(goal, actual.into());
|
||||
|
||||
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
@ -1,16 +1,19 @@
|
||||
use crate::solve::GoalSource;
|
||||
use rustc_type_ir::{self as ty, Interner, ProjectionPredicate};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::EvalCtxt;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
|
||||
use rustc_middle::ty::{self, ProjectionPredicate};
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::{Certainty, EvalCtxt, Goal, GoalSource, QueryResult};
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
#[instrument(level = "trace", skip(self), ret)]
|
||||
pub(super) fn compute_projection_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, ProjectionPredicate<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let tcx = self.interner();
|
||||
let projection_term = goal.predicate.projection_term.to_term(tcx);
|
||||
let goal = goal.with(
|
@ -1,22 +1,19 @@
|
||||
use std::mem;
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::dep_graph::dep_kinds;
|
||||
use rustc_middle::traits::solve::CacheData;
|
||||
use rustc_middle::traits::solve::EvaluationCache;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_next_trait_solver::solve::{CanonicalInput, Certainty, QueryResult};
|
||||
use rustc_session::Limit;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::Interner;
|
||||
use tracing::debug;
|
||||
|
||||
use super::inspect;
|
||||
use super::inspect::ProofTreeBuilder;
|
||||
use super::SolverMode;
|
||||
use crate::solve::FIXPOINT_STEP_LIMIT;
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::inspect::{self, ProofTreeBuilder};
|
||||
use crate::solve::{
|
||||
CacheData, CanonicalInput, Certainty, QueryResult, SolverMode, FIXPOINT_STEP_LIMIT,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct SolverLimit(usize);
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
#[orderable]
|
||||
@ -39,7 +36,7 @@ bitflags::bitflags! {
|
||||
struct StackEntry<I: Interner> {
|
||||
input: CanonicalInput<I>,
|
||||
|
||||
available_depth: Limit,
|
||||
available_depth: SolverLimit,
|
||||
|
||||
/// The maximum depth reached by this stack entry, only up-to date
|
||||
/// for the top of the stack and lazily updated for the rest.
|
||||
@ -168,19 +165,19 @@ impl<I: Interner> SearchGraph<I> {
|
||||
fn allowed_depth_for_nested(
|
||||
tcx: I,
|
||||
stack: &IndexVec<StackDepth, StackEntry<I>>,
|
||||
) -> Option<Limit> {
|
||||
) -> Option<SolverLimit> {
|
||||
if let Some(last) = stack.raw.last() {
|
||||
if last.available_depth.0 == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(if last.encountered_overflow {
|
||||
Limit(last.available_depth.0 / 4)
|
||||
SolverLimit(last.available_depth.0 / 4)
|
||||
} else {
|
||||
Limit(last.available_depth.0 - 1)
|
||||
SolverLimit(last.available_depth.0 - 1)
|
||||
})
|
||||
} else {
|
||||
Some(Limit(tcx.recursion_limit()))
|
||||
Some(SolverLimit(tcx.recursion_limit()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,34 +237,26 @@ impl<I: Interner> SearchGraph<I> {
|
||||
!entry.is_empty()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
|
||||
/// The trait solver behavior is different for coherence
|
||||
/// so we use a separate cache. Alternatively we could use
|
||||
/// a single cache and share it between coherence and ordinary
|
||||
/// trait solving.
|
||||
pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> {
|
||||
match self.mode {
|
||||
SolverMode::Normal => &tcx.new_solver_evaluation_cache,
|
||||
SolverMode::Coherence => &tcx.new_solver_coherence_evaluation_cache,
|
||||
}
|
||||
pub(super) fn global_cache(&self, tcx: I) -> I::EvaluationCache {
|
||||
tcx.evaluation_cache(self.mode)
|
||||
}
|
||||
|
||||
/// Probably the most involved method of the whole solver.
|
||||
///
|
||||
/// Given some goal which is proven via the `prove_goal` closure, this
|
||||
/// handles caching, overflow, and coinductive cycles.
|
||||
pub(super) fn with_new_goal(
|
||||
pub(super) fn with_new_goal<Infcx: SolverDelegate<Interner = I>>(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
input: CanonicalInput<TyCtxt<'tcx>>,
|
||||
inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
|
||||
mut prove_goal: impl FnMut(
|
||||
&mut Self,
|
||||
&mut ProofTreeBuilder<InferCtxt<'tcx>>,
|
||||
) -> QueryResult<TyCtxt<'tcx>>,
|
||||
) -> QueryResult<TyCtxt<'tcx>> {
|
||||
tcx: I,
|
||||
input: CanonicalInput<I>,
|
||||
inspect: &mut ProofTreeBuilder<Infcx>,
|
||||
mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<Infcx>) -> QueryResult<I>,
|
||||
) -> QueryResult<I> {
|
||||
self.check_invariants();
|
||||
// Check for overflow.
|
||||
let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else {
|
||||
@ -361,21 +350,20 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
|
||||
// not tracked by the cache key and from outside of this anon task, it
|
||||
// must not be added to the global cache. Notably, this is the case for
|
||||
// trait solver cycles participants.
|
||||
let ((final_entry, result), dep_node) =
|
||||
tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || {
|
||||
for _ in 0..FIXPOINT_STEP_LIMIT {
|
||||
match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) {
|
||||
StepResult::Done(final_entry, result) => return (final_entry, result),
|
||||
StepResult::HasChanged => debug!("fixpoint changed provisional results"),
|
||||
}
|
||||
let ((final_entry, result), dep_node) = tcx.with_cached_task(|| {
|
||||
for _ in 0..FIXPOINT_STEP_LIMIT {
|
||||
match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) {
|
||||
StepResult::Done(final_entry, result) => return (final_entry, result),
|
||||
StepResult::HasChanged => debug!("fixpoint changed provisional results"),
|
||||
}
|
||||
}
|
||||
|
||||
debug!("canonical cycle overflow");
|
||||
let current_entry = self.pop_stack();
|
||||
debug_assert!(current_entry.has_been_used.is_empty());
|
||||
let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false));
|
||||
(current_entry, result)
|
||||
});
|
||||
debug!("canonical cycle overflow");
|
||||
let current_entry = self.pop_stack();
|
||||
debug_assert!(current_entry.has_been_used.is_empty());
|
||||
let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false));
|
||||
(current_entry, result)
|
||||
});
|
||||
|
||||
let proof_tree = inspect.finalize_canonical_goal_evaluation(tcx);
|
||||
|
||||
@ -423,16 +411,17 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
|
||||
/// Try to fetch a previously computed result from the global cache,
|
||||
/// making sure to only do so if it would match the result of reevaluating
|
||||
/// this goal.
|
||||
fn lookup_global_cache(
|
||||
fn lookup_global_cache<Infcx: SolverDelegate<Interner = I>>(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
input: CanonicalInput<TyCtxt<'tcx>>,
|
||||
available_depth: Limit,
|
||||
inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
|
||||
) -> Option<QueryResult<TyCtxt<'tcx>>> {
|
||||
tcx: I,
|
||||
input: CanonicalInput<I>,
|
||||
available_depth: SolverLimit,
|
||||
inspect: &mut ProofTreeBuilder<Infcx>,
|
||||
) -> Option<QueryResult<I>> {
|
||||
let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self
|
||||
.global_cache(tcx)
|
||||
.get(tcx, input, self.stack.iter().map(|e| e.input), available_depth)?;
|
||||
// FIXME: Awkward `Limit -> usize -> Limit`.
|
||||
.get(tcx, input, self.stack.iter().map(|e| e.input), available_depth.0)?;
|
||||
|
||||
// If we're building a proof tree and the current cache entry does not
|
||||
// contain a proof tree, we do not use the entry but instead recompute
|
||||
@ -465,21 +454,22 @@ enum StepResult<I: Interner> {
|
||||
HasChanged,
|
||||
}
|
||||
|
||||
impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
|
||||
impl<I: Interner> SearchGraph<I> {
|
||||
/// When we encounter a coinductive cycle, we have to fetch the
|
||||
/// result of that cycle while we are still computing it. Because
|
||||
/// of this we continuously recompute the cycle until the result
|
||||
/// of the previous iteration is equal to the final result, at which
|
||||
/// point we are done.
|
||||
fn fixpoint_step_in_task<F>(
|
||||
fn fixpoint_step_in_task<Infcx, F>(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
input: CanonicalInput<TyCtxt<'tcx>>,
|
||||
inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>,
|
||||
tcx: I,
|
||||
input: CanonicalInput<I>,
|
||||
inspect: &mut ProofTreeBuilder<Infcx>,
|
||||
prove_goal: &mut F,
|
||||
) -> StepResult<TyCtxt<'tcx>>
|
||||
) -> StepResult<I>
|
||||
where
|
||||
F: FnMut(&mut Self, &mut ProofTreeBuilder<InferCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>,
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
F: FnMut(&mut Self, &mut ProofTreeBuilder<Infcx>) -> QueryResult<I>,
|
||||
{
|
||||
let result = prove_goal(self, inspect);
|
||||
let stack_entry = self.pop_stack();
|
||||
@ -533,15 +523,13 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
|
||||
}
|
||||
|
||||
fn response_no_constraints(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
goal: CanonicalInput<TyCtxt<'tcx>>,
|
||||
tcx: I,
|
||||
goal: CanonicalInput<I>,
|
||||
certainty: Certainty,
|
||||
) -> QueryResult<TyCtxt<'tcx>> {
|
||||
) -> QueryResult<I> {
|
||||
Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty))
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> SearchGraph<I> {
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
fn check_invariants(&self) {
|
||||
if !cfg!(debug_assertions) {
|
@ -1,60 +1,60 @@
|
||||
//! Dealing with trait goals, i.e. `T: Trait<'a, U>`.
|
||||
|
||||
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
|
||||
use super::assembly::{self, structural_traits, Candidate};
|
||||
use super::{EvalCtxt, GoalSource, SolverMode};
|
||||
use rustc_ast_ir::Movability;
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{LangItem, Movability};
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::NoSolution;
|
||||
use rustc_infer::traits::solve::MaybeCause;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::traits::solve::inspect::ProbeKind;
|
||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
|
||||
use rustc_middle::traits::{BuiltinImplSource, Reveal};
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
|
||||
use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use rustc_type_ir::inherent::*;
|
||||
use rustc_type_ir::lang_items::TraitSolverLangItem;
|
||||
use rustc_type_ir::visit::TypeVisitableExt as _;
|
||||
use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _};
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
fn self_ty(self) -> Ty<'tcx> {
|
||||
use crate::infcx::SolverDelegate;
|
||||
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
|
||||
use crate::solve::assembly::{self, Candidate};
|
||||
use crate::solve::inspect::ProbeKind;
|
||||
use crate::solve::{
|
||||
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
|
||||
NoSolution, QueryResult, Reveal, SolverMode,
|
||||
};
|
||||
|
||||
impl<Infcx, I> assembly::GoalKind<Infcx> for TraitPredicate<I>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
fn self_ty(self) -> I::Ty {
|
||||
self.self_ty()
|
||||
}
|
||||
|
||||
fn trait_ref(self, _: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
|
||||
fn trait_ref(self, _: I) -> ty::TraitRef<I> {
|
||||
self.trait_ref
|
||||
}
|
||||
|
||||
fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
|
||||
fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self {
|
||||
self.with_self_ty(tcx, self_ty)
|
||||
}
|
||||
|
||||
fn trait_def_id(self, _: TyCtxt<'tcx>) -> DefId {
|
||||
fn trait_def_id(self, _: I) -> I::DefId {
|
||||
self.def_id()
|
||||
}
|
||||
|
||||
fn consider_impl_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, TraitPredicate<I>>,
|
||||
impl_def_id: I::DefId,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let tcx = ecx.interner();
|
||||
|
||||
let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap();
|
||||
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup };
|
||||
if !drcx.args_may_unify(
|
||||
goal.predicate.trait_ref.args,
|
||||
impl_trait_header.trait_ref.skip_binder().args,
|
||||
) {
|
||||
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
|
||||
if !tcx
|
||||
.args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args)
|
||||
{
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// An upper bound of the certainty of this goal, used to lower the certainty
|
||||
// of reservation impl to ambiguous during coherence.
|
||||
let impl_polarity = impl_trait_header.polarity;
|
||||
let impl_polarity = tcx.impl_polarity(impl_def_id);
|
||||
let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
|
||||
// In intercrate mode, this is ambiguous. But outside of intercrate,
|
||||
// it's not a real impl.
|
||||
@ -77,14 +77,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| {
|
||||
let impl_args = ecx.fresh_args_for_item(impl_def_id);
|
||||
ecx.record_impl_args(impl_args);
|
||||
let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args);
|
||||
let impl_trait_ref = impl_trait_ref.instantiate(tcx, &impl_args);
|
||||
|
||||
ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?;
|
||||
let where_clause_bounds = tcx
|
||||
.predicates_of(impl_def_id)
|
||||
.instantiate(tcx, impl_args)
|
||||
.predicates
|
||||
.into_iter()
|
||||
.iter_instantiated(tcx, &impl_args)
|
||||
.map(|pred| goal.with(tcx, pred));
|
||||
ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds);
|
||||
|
||||
@ -93,21 +91,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_error_guaranteed_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
_guar: ErrorGuaranteed,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
_guar: I::ErrorGuaranteed,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
// FIXME: don't need to enter a probe here.
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
}
|
||||
|
||||
fn probe_and_match_goal_against_assumption(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
source: CandidateSource<'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
assumption: ty::Clause<'tcx>,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
source: CandidateSource<I>,
|
||||
goal: Goal<I, Self>,
|
||||
assumption: I::Clause,
|
||||
then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult<I>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if let Some(trait_clause) = assumption.as_trait_clause() {
|
||||
if trait_clause.def_id() == goal.predicate.def_id()
|
||||
&& trait_clause.polarity() == goal.predicate.polarity
|
||||
@ -130,9 +128,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_auto_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -159,7 +157,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
|
||||
if matches!(goal.param_env.reveal(), Reveal::All)
|
||||
|| matches!(ecx.solver_mode(), SolverMode::Coherence)
|
||||
|| ecx.can_define_opaque_ty(opaque_ty.def_id)
|
||||
|| opaque_ty
|
||||
.def_id
|
||||
.as_local()
|
||||
.is_some_and(|def_id| ecx.can_define_opaque_ty(def_id))
|
||||
{
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -173,9 +174,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_trait_alias_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -185,20 +186,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
let nested_obligations = tcx
|
||||
.predicates_of(goal.predicate.def_id())
|
||||
.instantiate(tcx, goal.predicate.trait_ref.args);
|
||||
.iter_instantiated(tcx, &goal.predicate.trait_ref.args)
|
||||
.map(|p| goal.with(tcx, p));
|
||||
// FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
|
||||
ecx.add_goals(
|
||||
GoalSource::Misc,
|
||||
nested_obligations.predicates.into_iter().map(|p| goal.with(tcx, p)),
|
||||
);
|
||||
ecx.add_goals(GoalSource::Misc, nested_obligations);
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
})
|
||||
}
|
||||
|
||||
fn consider_builtin_sized_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -211,9 +210,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_copy_clone_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -226,28 +225,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_pointer_like_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// The regions of a type don't affect the size of the type
|
||||
let tcx = ecx.interner();
|
||||
// We should erase regions from both the param-env and type, since both
|
||||
// may have infer regions. Specifically, after canonicalizing and instantiating,
|
||||
// early bound regions turn into region vars in both the new and old solver.
|
||||
let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty()));
|
||||
// But if there are inference variables, we have to wait until it's resolved.
|
||||
if key.has_non_region_infer() {
|
||||
if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() {
|
||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
||||
}
|
||||
|
||||
if let Ok(layout) = tcx.layout_of(key)
|
||||
&& layout.layout.is_pointer_like(&tcx.data_layout)
|
||||
{
|
||||
// FIXME: We could make this faster by making a no-constraints response
|
||||
if tcx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) {
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
} else {
|
||||
@ -256,9 +247,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_fn_ptr_trait_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
match goal.predicate.polarity {
|
||||
// impl FnPtr for FnPtr {}
|
||||
@ -287,10 +278,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -308,7 +299,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
};
|
||||
let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
|
||||
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output])
|
||||
ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output])
|
||||
});
|
||||
|
||||
let pred = tupled_inputs_and_output
|
||||
@ -328,10 +319,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_async_fn_trait_candidates(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
goal_kind: ty::ClosureKind,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -343,13 +334,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
goal.predicate.self_ty(),
|
||||
goal_kind,
|
||||
// This region doesn't matter because we're throwing away the coroutine type
|
||||
tcx.lifetimes.re_static,
|
||||
Region::new_static(tcx),
|
||||
)?;
|
||||
let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
|
||||
|AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::Sized, None),
|
||||
tcx.require_lang_item(TraitSolverLangItem::Sized),
|
||||
[output_coroutine_ty],
|
||||
)
|
||||
},
|
||||
@ -379,11 +370,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_async_fn_kind_helper_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else {
|
||||
bug!();
|
||||
panic!();
|
||||
};
|
||||
|
||||
let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
|
||||
@ -406,9 +397,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
/// impl Tuple for (T1, .., Tn) {}
|
||||
/// ```
|
||||
fn consider_builtin_tuple_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -422,9 +413,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_pointee_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -434,14 +425,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_future_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
|
||||
let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -460,14 +451,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
|
||||
let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -486,14 +477,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_fused_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
|
||||
let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -510,14 +501,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_async_iterator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
|
||||
let ty::Coroutine(def_id, _) = goal.predicate.self_ty().kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -536,15 +527,15 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_coroutine_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
let ty::Coroutine(def_id, args) = *self_ty.kind() else {
|
||||
let ty::Coroutine(def_id, args) = self_ty.kind() else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
@ -568,9 +559,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_discriminant_kind_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -581,9 +572,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_async_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -594,9 +585,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_destruct_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -610,9 +601,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
fn consider_builtin_transmute_candidate(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
@ -622,22 +613,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
// Erase regions because we compute layouts in `rustc_transmute`,
|
||||
// which will ICE for region vars.
|
||||
let args = ecx.interner().erase_regions(goal.predicate.trait_ref.args);
|
||||
|
||||
let Some(assume) =
|
||||
rustc_transmute::Assume::from_const(ecx.interner(), goal.param_env, args.const_at(2))
|
||||
else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
// FIXME: This actually should destructure the `Result` we get from transmutability and
|
||||
// register candiates. We probably need to register >1 since we may have an OR of ANDs.
|
||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
|
||||
let certainty = ecx.is_transmutable(
|
||||
rustc_transmute::Types { dst: args.type_at(0), src: args.type_at(1) },
|
||||
assume,
|
||||
goal.param_env,
|
||||
goal.predicate.trait_ref.args.type_at(0),
|
||||
goal.predicate.trait_ref.args.type_at(1),
|
||||
goal.predicate.trait_ref.args.const_at(2),
|
||||
)?;
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
|
||||
})
|
||||
@ -651,9 +634,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
/// impl<'a, T: Trait + 'a> Unsize<dyn Trait + 'a> for T {}
|
||||
/// ```
|
||||
fn consider_structural_builtin_unsize_candidates(
|
||||
ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> Vec<Candidate<TyCtxt<'tcx>>> {
|
||||
ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
goal: Goal<I, Self>,
|
||||
) -> Vec<Candidate<I>> {
|
||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
||||
return vec![];
|
||||
}
|
||||
@ -676,7 +659,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
|
||||
let goal = goal.with(ecx.interner(), (a_ty, b_ty));
|
||||
match (a_ty.kind(), b_ty.kind()) {
|
||||
(ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"),
|
||||
(ty::Infer(ty::TyVar(..)), ..) => panic!("unexpected infer {a_ty:?} {b_ty:?}"),
|
||||
|
||||
(_, ty::Infer(ty::TyVar(..))) => {
|
||||
result_to_single(ecx.forced_ambiguity(MaybeCause::Ambiguity))
|
||||
@ -684,24 +667,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
|
||||
// Trait upcasting, or `dyn Trait + Auto + 'a` -> `dyn Trait + 'b`.
|
||||
(
|
||||
&ty::Dynamic(a_data, a_region, ty::Dyn),
|
||||
&ty::Dynamic(b_data, b_region, ty::Dyn),
|
||||
ty::Dynamic(a_data, a_region, ty::Dyn),
|
||||
ty::Dynamic(b_data, b_region, ty::Dyn),
|
||||
) => ecx.consider_builtin_dyn_upcast_candidates(
|
||||
goal, a_data, a_region, b_data, b_region,
|
||||
),
|
||||
|
||||
// `T` -> `dyn Trait` unsizing.
|
||||
(_, &ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
|
||||
(_, ty::Dynamic(b_region, b_data, ty::Dyn)) => result_to_single(
|
||||
ecx.consider_builtin_unsize_to_dyn_candidate(goal, b_region, b_data),
|
||||
),
|
||||
|
||||
// `[T; N]` -> `[T]` unsizing
|
||||
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
|
||||
(ty::Array(a_elem_ty, ..), ty::Slice(b_elem_ty)) => {
|
||||
result_to_single(ecx.consider_builtin_array_unsize(goal, a_elem_ty, b_elem_ty))
|
||||
}
|
||||
|
||||
// `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
|
||||
(&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args))
|
||||
(ty::Adt(a_def, a_args), ty::Adt(b_def, b_args))
|
||||
if a_def.is_struct() && a_def == b_def =>
|
||||
{
|
||||
result_to_single(
|
||||
@ -710,7 +693,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
|
||||
// `(A, B, T)` -> `(A, B, U)` where `T: Unsize<U>`
|
||||
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
|
||||
(ty::Tuple(a_tys), ty::Tuple(b_tys))
|
||||
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
|
||||
{
|
||||
result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys))
|
||||
@ -722,7 +705,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
impl<Infcx, I> EvalCtxt<'_, Infcx>
|
||||
where
|
||||
Infcx: SolverDelegate<Interner = I>,
|
||||
I: Interner,
|
||||
{
|
||||
/// Trait upcasting allows for coercions between trait objects:
|
||||
/// ```ignore (builtin impl example)
|
||||
/// trait Super {}
|
||||
@ -734,12 +721,12 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// ```
|
||||
fn consider_builtin_dyn_upcast_candidates(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
a_region: ty::Region<'tcx>,
|
||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
b_region: ty::Region<'tcx>,
|
||||
) -> Vec<Candidate<TyCtxt<'tcx>>> {
|
||||
goal: Goal<I, (I::Ty, I::Ty)>,
|
||||
a_data: I::BoundExistentialPredicates,
|
||||
a_region: I::Region,
|
||||
b_data: I::BoundExistentialPredicates,
|
||||
b_region: I::Region,
|
||||
) -> Vec<Candidate<I>> {
|
||||
let tcx = self.interner();
|
||||
let Goal { predicate: (a_ty, _b_ty), .. } = goal;
|
||||
|
||||
@ -757,7 +744,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
a_data.principal(),
|
||||
));
|
||||
} else if let Some(a_principal) = a_data.principal() {
|
||||
for new_a_principal in supertraits(tcx, a_principal.with_self_ty(tcx, a_ty)).skip(1) {
|
||||
for new_a_principal in
|
||||
Infcx::elaborate_supertraits(self.interner(), a_principal.with_self_ty(tcx, a_ty))
|
||||
.skip(1)
|
||||
{
|
||||
responses.extend(self.consider_builtin_upcast_to_principal(
|
||||
goal,
|
||||
CandidateSource::BuiltinImpl(BuiltinImplSource::TraitUpcasting),
|
||||
@ -777,15 +767,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
|
||||
fn consider_builtin_unsize_to_dyn_candidate(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
b_region: ty::Region<'tcx>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
goal: Goal<I, (I::Ty, I::Ty)>,
|
||||
b_data: I::BoundExistentialPredicates,
|
||||
b_region: I::Region,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let tcx = self.interner();
|
||||
let Goal { predicate: (a_ty, _), .. } = goal;
|
||||
|
||||
// Can only unsize to an object-safe trait.
|
||||
if b_data.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) {
|
||||
if b_data.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
@ -794,7 +784,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// (i.e. the principal, all of the associated types match, and any auto traits)
|
||||
ecx.add_goals(
|
||||
GoalSource::ImplWhereBound,
|
||||
b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
|
||||
b_data.into_iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
|
||||
);
|
||||
|
||||
// The type must be `Sized` to be unsized.
|
||||
@ -802,7 +792,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
GoalSource::ImplWhereBound,
|
||||
goal.with(
|
||||
tcx,
|
||||
ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [a_ty]),
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(TraitSolverLangItem::Sized),
|
||||
[a_ty],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@ -814,24 +808,26 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
|
||||
fn consider_builtin_upcast_to_principal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
source: CandidateSource<'tcx>,
|
||||
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
a_region: ty::Region<'tcx>,
|
||||
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
||||
b_region: ty::Region<'tcx>,
|
||||
upcast_principal: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
goal: Goal<I, (I::Ty, I::Ty)>,
|
||||
source: CandidateSource<I>,
|
||||
a_data: I::BoundExistentialPredicates,
|
||||
a_region: I::Region,
|
||||
b_data: I::BoundExistentialPredicates,
|
||||
b_region: I::Region,
|
||||
upcast_principal: Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let param_env = goal.param_env;
|
||||
|
||||
// We may upcast to auto traits that are either explicitly listed in
|
||||
// the object type's bounds, or implied by the principal trait ref's
|
||||
// supertraits.
|
||||
let a_auto_traits: FxIndexSet<DefId> = a_data
|
||||
let a_auto_traits: FxIndexSet<I::DefId> = a_data
|
||||
.auto_traits()
|
||||
.into_iter()
|
||||
.chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| {
|
||||
self.interner()
|
||||
.supertrait_def_ids(principal_def_id)
|
||||
.into_iter()
|
||||
.filter(|def_id| self.interner().trait_is_auto(*def_id))
|
||||
}))
|
||||
.collect();
|
||||
@ -841,9 +837,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// having any inference side-effects. We process obligations because
|
||||
// unification may initially succeed due to deferred projection equality.
|
||||
let projection_may_match =
|
||||
|ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
source_projection: ty::PolyExistentialProjection<'tcx>,
|
||||
target_projection: ty::PolyExistentialProjection<'tcx>| {
|
||||
|ecx: &mut EvalCtxt<'_, Infcx>,
|
||||
source_projection: ty::Binder<I, ty::ExistentialProjection<I>>,
|
||||
target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
|
||||
source_projection.item_def_id() == target_projection.item_def_id()
|
||||
&& ecx
|
||||
.probe(|_| ProbeKind::UpcastProjectionCompatibility)
|
||||
@ -875,7 +871,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
ty::ExistentialPredicate::Projection(target_projection) => {
|
||||
let target_projection = bound.rebind(target_projection);
|
||||
let mut matching_projections =
|
||||
a_data.projection_bounds().filter(|source_projection| {
|
||||
a_data.projection_bounds().into_iter().filter(|source_projection| {
|
||||
projection_may_match(ecx, *source_projection, target_projection)
|
||||
});
|
||||
let Some(source_projection) = matching_projections.next() else {
|
||||
@ -900,11 +896,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// Also require that a_ty's lifetime outlives b_ty's lifetime.
|
||||
ecx.add_goal(
|
||||
GoalSource::ImplWhereBound,
|
||||
Goal::new(
|
||||
ecx.interner(),
|
||||
param_env,
|
||||
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
|
||||
),
|
||||
Goal::new(ecx.interner(), param_env, ty::OutlivesPredicate(a_region, b_region)),
|
||||
);
|
||||
|
||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||
@ -921,10 +913,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// `#[rustc_deny_explicit_impl]` in this case.
|
||||
fn consider_builtin_array_unsize(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
a_elem_ty: Ty<'tcx>,
|
||||
b_elem_ty: Ty<'tcx>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
goal: Goal<I, (I::Ty, I::Ty)>,
|
||||
a_elem_ty: I::Ty,
|
||||
b_elem_ty: I::Ty,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
self.eq(goal.param_env, a_elem_ty, b_elem_ty)?;
|
||||
self.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
||||
@ -945,26 +937,25 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// ```
|
||||
fn consider_builtin_struct_unsize(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
def: ty::AdtDef<'tcx>,
|
||||
a_args: ty::GenericArgsRef<'tcx>,
|
||||
b_args: ty::GenericArgsRef<'tcx>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
goal: Goal<I, (I::Ty, I::Ty)>,
|
||||
def: I::AdtDef,
|
||||
a_args: I::GenericArgs,
|
||||
b_args: I::GenericArgs,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let tcx = self.interner();
|
||||
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
|
||||
|
||||
let unsizing_params = tcx.unsizing_params_for_adt(def.did());
|
||||
let unsizing_params = tcx.unsizing_params_for_adt(def.def_id());
|
||||
// We must be unsizing some type parameters. This also implies
|
||||
// that the struct has a tail field.
|
||||
if unsizing_params.is_empty() {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let tail_field = def.non_enum_variant().tail();
|
||||
let tail_field_ty = tcx.type_of(tail_field.did);
|
||||
let tail_field_ty = def.struct_tail_ty(tcx).unwrap();
|
||||
|
||||
let a_tail_ty = tail_field_ty.instantiate(tcx, a_args);
|
||||
let b_tail_ty = tail_field_ty.instantiate(tcx, b_args);
|
||||
let a_tail_ty = tail_field_ty.instantiate(tcx, &a_args);
|
||||
let b_tail_ty = tail_field_ty.instantiate(tcx, &b_args);
|
||||
|
||||
// Instantiate just the unsizing params from B into A. The type after
|
||||
// this instantiation must be equal to B. This is so we don't unsize
|
||||
@ -973,7 +964,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
a_args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { a }),
|
||||
.map(|(i, a)| if unsizing_params.contains(i as u32) { b_args[i] } else { *a }),
|
||||
);
|
||||
let unsized_a_ty = Ty::new_adt(tcx, def, new_a_args);
|
||||
|
||||
@ -986,7 +977,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
tcx,
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::Unsize, None),
|
||||
tcx.require_lang_item(TraitSolverLangItem::Unsize),
|
||||
[a_tail_ty, b_tail_ty],
|
||||
),
|
||||
),
|
||||
@ -1007,10 +998,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// ```
|
||||
fn consider_builtin_tuple_unsize(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
|
||||
a_tys: &'tcx ty::List<Ty<'tcx>>,
|
||||
b_tys: &'tcx ty::List<Ty<'tcx>>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
goal: Goal<I, (I::Ty, I::Ty)>,
|
||||
a_tys: I::Tys,
|
||||
b_tys: I::Tys,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
let tcx = self.interner();
|
||||
let Goal { predicate: (_a_ty, b_ty), .. } = goal;
|
||||
|
||||
@ -1029,7 +1020,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
tcx,
|
||||
ty::TraitRef::new(
|
||||
tcx,
|
||||
tcx.require_lang_item(LangItem::Unsize, None),
|
||||
tcx.require_lang_item(TraitSolverLangItem::Unsize),
|
||||
[a_last_ty, b_last_ty],
|
||||
),
|
||||
),
|
||||
@ -1044,10 +1035,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
// the type's constituent types.
|
||||
fn disqualify_auto_trait_candidate_due_to_possible_impl(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
) -> Option<Result<Candidate<TyCtxt<'tcx>>, NoSolution>> {
|
||||
goal: Goal<I, TraitPredicate<I>>,
|
||||
) -> Option<Result<Candidate<I>, NoSolution>> {
|
||||
let self_ty = goal.predicate.self_ty();
|
||||
match *self_ty.kind() {
|
||||
match self_ty.kind() {
|
||||
// Stall int and float vars until they are resolved to a concrete
|
||||
// numerical type. That's because the check for impls below treats
|
||||
// int vars as matching any impl. Even if we filtered such impls,
|
||||
@ -1065,13 +1056,15 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
| ty::Alias(ty::Projection | ty::Weak | ty::Inherent, ..)
|
||||
| ty::Placeholder(..) => Some(Err(NoSolution)),
|
||||
|
||||
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
|
||||
ty::Infer(_) | ty::Bound(_, _) => panic!("unexpected type `{self_ty:?}`"),
|
||||
|
||||
// Coroutines have one special built-in candidate, `Unpin`, which
|
||||
// takes precedence over the structural auto trait candidate being
|
||||
// assembled.
|
||||
ty::Coroutine(def_id, _)
|
||||
if self.interner().is_lang_item(goal.predicate.def_id(), LangItem::Unpin) =>
|
||||
if self
|
||||
.interner()
|
||||
.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::Unpin) =>
|
||||
{
|
||||
match self.interner().coroutine_movability(def_id) {
|
||||
Movability::Static => Some(Err(NoSolution)),
|
||||
@ -1144,13 +1137,13 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
/// wrapped in one.
|
||||
fn probe_and_evaluate_goal_for_constituent_tys(
|
||||
&mut self,
|
||||
source: CandidateSource<'tcx>,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
source: CandidateSource<I>,
|
||||
goal: Goal<I, TraitPredicate<I>>,
|
||||
constituent_tys: impl Fn(
|
||||
&EvalCtxt<'_, InferCtxt<'tcx>>,
|
||||
Ty<'tcx>,
|
||||
) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
|
||||
) -> Result<Candidate<TyCtxt<'tcx>>, NoSolution> {
|
||||
&EvalCtxt<'_, Infcx>,
|
||||
I::Ty,
|
||||
) -> Result<Vec<ty::Binder<I, I::Ty>>, NoSolution>,
|
||||
) -> Result<Candidate<I>, NoSolution> {
|
||||
self.probe_trait_candidate(source).enter(|ecx| {
|
||||
ecx.add_goals(
|
||||
GoalSource::ImplWhereBound,
|
||||
@ -1173,8 +1166,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
pub(super) fn compute_trait_goal(
|
||||
&mut self,
|
||||
goal: Goal<'tcx, TraitPredicate<'tcx>>,
|
||||
) -> QueryResult<'tcx> {
|
||||
goal: Goal<I, TraitPredicate<I>>,
|
||||
) -> QueryResult<I> {
|
||||
let candidates = self.assemble_and_evaluate_candidates(goal);
|
||||
self.merge_candidates(candidates)
|
||||
}
|
12
compiler/rustc_trait_selection/src/solve.rs
Normal file
12
compiler/rustc_trait_selection/src/solve.rs
Normal file
@ -0,0 +1,12 @@
|
||||
pub use rustc_next_trait_solver::solve::*;
|
||||
|
||||
mod fulfill;
|
||||
mod infcx;
|
||||
pub mod inspect;
|
||||
mod normalize;
|
||||
mod select;
|
||||
|
||||
pub use fulfill::{FulfillmentCtxt, NextSolverError};
|
||||
pub(crate) use normalize::deeply_normalize_for_diagnostics;
|
||||
pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
|
||||
pub use select::InferCtxtSelectExt;
|
@ -12,13 +12,14 @@ use rustc_infer::traits::{
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError};
|
||||
|
||||
use super::eval_ctxt::GenerateProofTree;
|
||||
use super::infcx::SolverDelegate;
|
||||
use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
use super::{Certainty, InferCtxtEvalExt};
|
||||
use super::Certainty;
|
||||
|
||||
/// A trait engine using the new trait solver.
|
||||
///
|
||||
@ -83,7 +84,9 @@ impl<'tcx> ObligationStorage<'tcx> {
|
||||
// change.
|
||||
self.overflowed.extend(self.pending.extract_if(|o| {
|
||||
let goal = o.clone().into();
|
||||
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::No).0;
|
||||
let result = <&SolverDelegate<'tcx>>::from(infcx)
|
||||
.evaluate_root_goal(goal, GenerateProofTree::No)
|
||||
.0;
|
||||
match result {
|
||||
Ok((has_changed, _)) => has_changed,
|
||||
_ => false,
|
||||
@ -165,7 +168,9 @@ where
|
||||
let mut has_changed = false;
|
||||
for obligation in self.obligations.unstalled_for_select() {
|
||||
let goal = obligation.clone().into();
|
||||
let result = infcx.evaluate_root_goal(goal, GenerateProofTree::No).0;
|
||||
let result = <&SolverDelegate<'tcx>>::from(infcx)
|
||||
.evaluate_root_goal(goal, GenerateProofTree::No)
|
||||
.0;
|
||||
self.inspect_evaluated_obligation(infcx, &obligation, &result);
|
||||
let (changed, certainty) = match result {
|
||||
Ok(result) => result,
|
||||
@ -288,7 +293,10 @@ fn fulfillment_error_for_stalled<'tcx>(
|
||||
root_obligation: PredicateObligation<'tcx>,
|
||||
) -> FulfillmentError<'tcx> {
|
||||
let (code, refine_obligation) = infcx.probe(|_| {
|
||||
match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No).0 {
|
||||
match <&SolverDelegate<'tcx>>::from(infcx)
|
||||
.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::No)
|
||||
.0
|
||||
{
|
||||
Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
|
||||
(FulfillmentErrorCode::Ambiguity { overflow: None }, true)
|
||||
}
|
||||
|
435
compiler/rustc_trait_selection/src/solve/infcx.rs
Normal file
435
compiler/rustc_trait_selection/src/solve/infcx.rs
Normal file
@ -0,0 +1,435 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
|
||||
use rustc_infer::infer::canonical::{
|
||||
Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues,
|
||||
};
|
||||
use rustc_infer::infer::{
|
||||
BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt,
|
||||
};
|
||||
use rustc_infer::traits::solve::Goal;
|
||||
use rustc_infer::traits::util::supertraits;
|
||||
use rustc_infer::traits::{ObligationCause, Reveal};
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
|
||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||
use rustc_type_ir::relate::Relate;
|
||||
use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode};
|
||||
|
||||
use crate::traits::coherence::trait_ref_is_knowable;
|
||||
use crate::traits::specialization_graph;
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct SolverDelegate<'tcx>(InferCtxt<'tcx>);
|
||||
|
||||
impl<'a, 'tcx> From<&'a InferCtxt<'tcx>> for &'a SolverDelegate<'tcx> {
|
||||
fn from(infcx: &'a InferCtxt<'tcx>) -> Self {
|
||||
// SAFETY: `repr(transparent)`
|
||||
unsafe { std::mem::transmute(infcx) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Deref for SolverDelegate<'tcx> {
|
||||
type Target = InferCtxt<'tcx>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> rustc_next_trait_solver::infcx::SolverDelegate for SolverDelegate<'tcx> {
|
||||
type Interner = TyCtxt<'tcx>;
|
||||
|
||||
fn interner(&self) -> TyCtxt<'tcx> {
|
||||
self.0.tcx
|
||||
}
|
||||
|
||||
type Span = Span;
|
||||
|
||||
fn solver_mode(&self) -> ty::solve::SolverMode {
|
||||
match self.intercrate {
|
||||
true => SolverMode::Coherence,
|
||||
false => SolverMode::Normal,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_with_canonical<V>(
|
||||
interner: TyCtxt<'tcx>,
|
||||
solver_mode: SolverMode,
|
||||
canonical: &Canonical<'tcx, V>,
|
||||
) -> (Self, V, CanonicalVarValues<'tcx>)
|
||||
where
|
||||
V: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
let (infcx, value, vars) = interner
|
||||
.infer_ctxt()
|
||||
.with_next_trait_solver(true)
|
||||
.intercrate(match solver_mode {
|
||||
SolverMode::Normal => false,
|
||||
SolverMode::Coherence => true,
|
||||
})
|
||||
.build_with_canonical(DUMMY_SP, canonical);
|
||||
(SolverDelegate(infcx), value, vars)
|
||||
}
|
||||
|
||||
fn universe(&self) -> ty::UniverseIndex {
|
||||
self.0.universe()
|
||||
}
|
||||
|
||||
fn create_next_universe(&self) -> ty::UniverseIndex {
|
||||
self.0.create_next_universe()
|
||||
}
|
||||
|
||||
fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> {
|
||||
// FIXME(BoxyUwU): this is kind of jank and means that printing unresolved
|
||||
// ty infers will give you the universe of the var it resolved to not the universe
|
||||
// it actually had. It also means that if you have a `?0.1` and infer it to `u8` then
|
||||
// try to print out `?0.1` it will just print `?0`.
|
||||
match self.0.probe_ty_var(vid) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> {
|
||||
match self.0.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> {
|
||||
// Same issue as with `universe_of_ty`
|
||||
match self.0.probe_const_var(ct) {
|
||||
Err(universe) => Some(universe),
|
||||
Ok(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
|
||||
self.0.root_var(var)
|
||||
}
|
||||
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
|
||||
self.0.root_const_var(var)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> {
|
||||
match self.0.probe_ty_var(vid) {
|
||||
Ok(ty) => ty,
|
||||
Err(_) => Ty::new_var(self.0.tcx, self.0.root_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> {
|
||||
self.0.opportunistic_resolve_int_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> {
|
||||
self.0.opportunistic_resolve_float_var(vid)
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> {
|
||||
match self.0.probe_const_var(vid) {
|
||||
Ok(ct) => ct,
|
||||
Err(_) => ty::Const::new_var(self.0.tcx, self.0.root_const_var(vid)),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> {
|
||||
match self.0.probe_effect_var(vid) {
|
||||
Some(ct) => ct,
|
||||
None => ty::Const::new_infer(
|
||||
self.0.tcx,
|
||||
ty::InferConst::EffectVar(self.0.root_effect_var(vid)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
|
||||
self.0
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.unwrap_region_constraints()
|
||||
.opportunistic_resolve_var(self.0.tcx, vid)
|
||||
}
|
||||
|
||||
fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
|
||||
self.0.defining_opaque_types()
|
||||
}
|
||||
|
||||
fn next_ty_infer(&self) -> Ty<'tcx> {
|
||||
self.0.next_ty_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn next_const_infer(&self) -> ty::Const<'tcx> {
|
||||
self.0.next_const_var(DUMMY_SP)
|
||||
}
|
||||
|
||||
fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
|
||||
self.0.fresh_args_for_item(DUMMY_SP, def_id)
|
||||
}
|
||||
|
||||
fn fresh_var_for_kind_with_span(
|
||||
&self,
|
||||
arg: ty::GenericArg<'tcx>,
|
||||
span: Span,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
match arg.unpack() {
|
||||
ty::GenericArgKind::Lifetime(_) => {
|
||||
self.next_region_var(RegionVariableOrigin::MiscVariable(span)).into()
|
||||
}
|
||||
ty::GenericArgKind::Type(_) => self.next_ty_var(span).into(),
|
||||
ty::GenericArgKind::Const(_) => self.next_const_var(span).into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
) -> T {
|
||||
self.0.instantiate_binder_with_fresh_vars(
|
||||
DUMMY_SP,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<'tcx, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U {
|
||||
self.0.enter_forall(value, f)
|
||||
}
|
||||
|
||||
fn relate<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs)
|
||||
}
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> {
|
||||
self.0
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq_structurally_relating_aliases_no_trace(lhs, rhs)
|
||||
}
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.0.resolve_vars_if_possible(value)
|
||||
}
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T {
|
||||
self.0.probe(|_| probe())
|
||||
}
|
||||
|
||||
fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> {
|
||||
self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution)
|
||||
}
|
||||
|
||||
fn elaborate_supertraits(
|
||||
interner: TyCtxt<'tcx>,
|
||||
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
|
||||
) -> impl Iterator<Item = ty::Binder<'tcx, ty::TraitRef<'tcx>>> {
|
||||
supertraits(interner, trait_ref)
|
||||
}
|
||||
|
||||
fn try_const_eval_resolve(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
unevaluated: ty::UnevaluatedConst<'tcx>,
|
||||
) -> Option<ty::Const<'tcx>> {
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
|
||||
Ok(Some(val)) => Some(ty::Const::new_value(
|
||||
self.tcx,
|
||||
val,
|
||||
self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
|
||||
)),
|
||||
Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None,
|
||||
Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())),
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) {
|
||||
self.0.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup)
|
||||
}
|
||||
|
||||
fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) {
|
||||
self.0.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy());
|
||||
}
|
||||
|
||||
fn well_formed_goals(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
arg: ty::GenericArg<'tcx>,
|
||||
) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
|
||||
crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg).map(|obligations| {
|
||||
obligations.into_iter().map(|obligation| obligation.into()).collect()
|
||||
})
|
||||
}
|
||||
|
||||
fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
|
||||
self.0.clone_opaque_types_for_query_response()
|
||||
}
|
||||
|
||||
fn make_deduplicated_outlives_constraints(
|
||||
&self,
|
||||
) -> Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> {
|
||||
// Cannot use `take_registered_region_obligations` as we may compute the response
|
||||
// inside of a `probe` whenever we have multiple choices inside of the solver.
|
||||
let region_obligations = self.0.inner.borrow().region_obligations().to_owned();
|
||||
let region_constraints = self.0.with_region_constraints(|region_constraints| {
|
||||
make_query_region_constraints(
|
||||
self.tcx,
|
||||
region_obligations
|
||||
.iter()
|
||||
.map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())),
|
||||
region_constraints,
|
||||
)
|
||||
});
|
||||
|
||||
assert_eq!(region_constraints.member_constraints, vec![]);
|
||||
|
||||
let mut seen = FxHashSet::default();
|
||||
region_constraints
|
||||
.outlives
|
||||
.into_iter()
|
||||
.filter(|&(outlives, _)| seen.insert(outlives))
|
||||
.map(|(outlives, _)| outlives)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn instantiate_canonical<V>(
|
||||
&self,
|
||||
canonical: Canonical<'tcx, V>,
|
||||
values: CanonicalVarValues<'tcx>,
|
||||
) -> V
|
||||
where
|
||||
V: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
canonical.instantiate(self.tcx, &values)
|
||||
}
|
||||
|
||||
fn instantiate_canonical_var_with_infer(
|
||||
&self,
|
||||
cv_info: CanonicalVarInfo<'tcx>,
|
||||
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
|
||||
) -> ty::GenericArg<'tcx> {
|
||||
self.0.instantiate_canonical_var(DUMMY_SP, cv_info, universe_map)
|
||||
}
|
||||
|
||||
fn insert_hidden_type(
|
||||
&self,
|
||||
opaque_type_key: ty::OpaqueTypeKey<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) -> Result<(), NoSolution> {
|
||||
self.0
|
||||
.insert_hidden_type(opaque_type_key, DUMMY_SP, param_env, hidden_ty, goals)
|
||||
.map_err(|_| NoSolution)
|
||||
}
|
||||
|
||||
fn add_item_bounds_for_hidden_type(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
args: ty::GenericArgsRef<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
hidden_ty: Ty<'tcx>,
|
||||
goals: &mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
) {
|
||||
self.0.add_item_bounds_for_hidden_type(def_id, args, param_env, hidden_ty, goals);
|
||||
}
|
||||
|
||||
fn inject_new_hidden_type_unchecked(&self, key: ty::OpaqueTypeKey<'tcx>, hidden_ty: Ty<'tcx>) {
|
||||
self.0.inject_new_hidden_type_unchecked(
|
||||
key,
|
||||
ty::OpaqueHiddenType { ty: hidden_ty, span: DUMMY_SP },
|
||||
)
|
||||
}
|
||||
|
||||
fn reset_opaque_types(&self) {
|
||||
let _ = self.take_opaque_types();
|
||||
}
|
||||
|
||||
fn trait_ref_is_knowable<E: std::fmt::Debug>(
|
||||
&self,
|
||||
trait_ref: ty::TraitRef<'tcx>,
|
||||
lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result<Ty<'tcx>, E>,
|
||||
) -> Result<bool, E> {
|
||||
trait_ref_is_knowable(&self.0, trait_ref, lazily_normalize_ty)
|
||||
.map(|is_knowable| is_knowable.is_ok())
|
||||
}
|
||||
|
||||
fn fetch_eligible_assoc_item(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
goal_trait_ref: ty::TraitRef<'tcx>,
|
||||
trait_assoc_def_id: DefId,
|
||||
impl_def_id: DefId,
|
||||
) -> Result<Option<DefId>, NoSolution> {
|
||||
let node_item = specialization_graph::assoc_def(self.tcx, 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
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME: Check for defaultness here may cause diagnostics problems.
|
||||
if eligible { Ok(Some(node_item.item.def_id)) } else { Ok(None) }
|
||||
}
|
||||
|
||||
fn is_transmutable(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
dst: Ty<'tcx>,
|
||||
src: Ty<'tcx>,
|
||||
assume: ty::Const<'tcx>,
|
||||
) -> Result<Certainty, NoSolution> {
|
||||
// Erase regions because we compute layouts in `rustc_transmute`,
|
||||
// which will ICE for region vars.
|
||||
let (dst, src) = self.tcx.erase_regions((dst, src));
|
||||
|
||||
let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, param_env, assume) else {
|
||||
return Err(NoSolution);
|
||||
};
|
||||
|
||||
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
|
||||
match rustc_transmute::TransmuteTypeEnv::new(&self.0).is_transmutable(
|
||||
ObligationCause::dummy(),
|
||||
rustc_transmute::Types { src, dst },
|
||||
assume,
|
||||
) {
|
||||
rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
|
||||
rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
|
||||
}
|
||||
}
|
||||
}
|
4
compiler/rustc_trait_selection/src/solve/inspect.rs
Normal file
4
compiler/rustc_trait_selection/src/solve/inspect.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub use rustc_next_trait_solver::solve::inspect::*;
|
||||
|
||||
mod analyse;
|
||||
pub use analyse::*;
|
@ -13,18 +13,16 @@ use rustc_ast_ir::try_visit;
|
||||
use rustc_ast_ir::visit::VisitorResult;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
use rustc_middle::traits::solve::{inspect, QueryResult};
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, MaybeCause};
|
||||
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult};
|
||||
use rustc_middle::traits::ObligationCause;
|
||||
use rustc_middle::ty::{TyCtxt, TypeFoldable};
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_next_trait_solver::resolve::EagerResolver;
|
||||
use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state};
|
||||
use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use crate::solve::eval_ctxt::canonical;
|
||||
use crate::solve::{EvalCtxt, GoalEvaluationKind, GoalSource};
|
||||
use crate::solve::{GenerateProofTree, InferCtxtEvalExt};
|
||||
use crate::solve::infcx::SolverDelegate;
|
||||
use crate::traits::ObligationCtxt;
|
||||
|
||||
pub struct InspectConfig {
|
||||
@ -32,7 +30,7 @@ pub struct InspectConfig {
|
||||
}
|
||||
|
||||
pub struct InspectGoal<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
infcx: &'a SolverDelegate<'tcx>,
|
||||
depth: usize,
|
||||
orig_values: Vec<ty::GenericArg<'tcx>>,
|
||||
goal: Goal<'tcx, ty::Predicate<'tcx>>,
|
||||
@ -162,16 +160,10 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
||||
match **step {
|
||||
inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
|
||||
source,
|
||||
canonical::instantiate_canonical_state(
|
||||
infcx,
|
||||
span,
|
||||
param_env,
|
||||
&mut orig_values,
|
||||
goal,
|
||||
),
|
||||
instantiate_canonical_state(infcx, span, param_env, &mut orig_values, goal),
|
||||
)),
|
||||
inspect::ProbeStep::RecordImplArgs { impl_args } => {
|
||||
opt_impl_args = Some(canonical::instantiate_canonical_state(
|
||||
opt_impl_args = Some(instantiate_canonical_state(
|
||||
infcx,
|
||||
span,
|
||||
param_env,
|
||||
@ -184,13 +176,8 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
let () = canonical::instantiate_canonical_state(
|
||||
infcx,
|
||||
span,
|
||||
param_env,
|
||||
&mut orig_values,
|
||||
self.final_state,
|
||||
);
|
||||
let () =
|
||||
instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state);
|
||||
|
||||
if let Some(term_hack) = self.goal.normalizes_to_term_hack {
|
||||
// FIXME: We ignore the expected term of `NormalizesTo` goals
|
||||
@ -219,16 +206,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
|
||||
// instantiating the candidate it is already constrained to the result of another
|
||||
// candidate.
|
||||
let proof_tree = infcx
|
||||
.probe(|_| {
|
||||
EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
|
||||
ecx.evaluate_goal_raw(
|
||||
GoalEvaluationKind::Root,
|
||||
GoalSource::Misc,
|
||||
goal,
|
||||
)
|
||||
})
|
||||
})
|
||||
.1;
|
||||
.probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes).1);
|
||||
InspectGoal::new(
|
||||
infcx,
|
||||
self.goal.depth + 1,
|
||||
@ -388,6 +366,8 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
|
||||
normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>,
|
||||
source: GoalSource,
|
||||
) -> Self {
|
||||
let infcx = <&SolverDelegate<'tcx>>::from(infcx);
|
||||
|
||||
let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root;
|
||||
let result = evaluation.result.and_then(|ok| {
|
||||
if let Some(term_hack) = normalizes_to_term_hack {
|
||||
@ -449,7 +429,8 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
depth: usize,
|
||||
visitor: &mut V,
|
||||
) -> V::Result {
|
||||
let (_, proof_tree) = self.evaluate_root_goal(goal, GenerateProofTree::Yes);
|
||||
let (_, proof_tree) =
|
||||
<&SolverDelegate<'tcx>>::from(self).evaluate_root_goal(goal, GenerateProofTree::Yes);
|
||||
let proof_tree = proof_tree.unwrap();
|
||||
visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, None, GoalSource::Misc))
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
pub use rustc_middle::traits::solve::inspect::*;
|
||||
|
||||
mod build;
|
||||
pub(in crate::solve) use build::*;
|
||||
|
||||
mod analyse;
|
||||
pub use analyse::*;
|
@ -19,7 +19,7 @@ use super::{
|
||||
};
|
||||
|
||||
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
||||
use crate::solve::InferCtxtSelectExt;
|
||||
use crate::solve::InferCtxtSelectExt as _;
|
||||
use crate::traits::error_reporting::TypeErrCtxtExt;
|
||||
use crate::traits::normalize::normalize_with_depth;
|
||||
use crate::traits::normalize::normalize_with_depth_to;
|
||||
|
@ -1,77 +0,0 @@
|
||||
use crate::fold::TypeFoldable;
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::{Goal, NoSolution};
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
pub trait InferCtxtLike: Sized {
|
||||
type Interner: Interner;
|
||||
|
||||
fn interner(&self) -> Self::Interner;
|
||||
|
||||
fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>;
|
||||
fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>;
|
||||
|
||||
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid;
|
||||
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid;
|
||||
|
||||
fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_float_var(
|
||||
&self,
|
||||
vid: ty::FloatVid,
|
||||
) -> <Self::Interner as Interner>::Ty;
|
||||
fn opportunistic_resolve_ct_var(
|
||||
&self,
|
||||
vid: ty::ConstVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_effect_var(
|
||||
&self,
|
||||
vid: ty::EffectVid,
|
||||
) -> <Self::Interner as Interner>::Const;
|
||||
fn opportunistic_resolve_lt_var(
|
||||
&self,
|
||||
vid: ty::RegionVid,
|
||||
) -> <Self::Interner as Interner>::Region;
|
||||
|
||||
fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
|
||||
|
||||
fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
|
||||
fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
|
||||
fn fresh_args_for_item(
|
||||
&self,
|
||||
def_id: <Self::Interner as Interner>::DefId,
|
||||
) -> <Self::Interner as Interner>::GenericArgs;
|
||||
|
||||
fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
) -> T;
|
||||
|
||||
fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>(
|
||||
&self,
|
||||
value: ty::Binder<Self::Interner, T>,
|
||||
f: impl FnOnce(T) -> U,
|
||||
) -> U;
|
||||
|
||||
fn relate<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
variance: ty::Variance,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
|
||||
&self,
|
||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
||||
lhs: T,
|
||||
rhs: T,
|
||||
) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>;
|
||||
|
||||
fn resolve_vars_if_possible<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<Self::Interner>;
|
||||
|
||||
fn probe<T>(&self, probe: impl FnOnce() -> T) -> T;
|
||||
}
|
@ -8,9 +8,11 @@ use std::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
|
||||
use rustc_ast_ir::Mutability;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
||||
use crate::fold::{TypeFoldable, TypeSuperFoldable};
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::{CacheData, CanonicalInput, QueryResult, Reveal};
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
|
||||
|
||||
@ -27,10 +29,14 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||
+ Relate<I>
|
||||
+ Flags
|
||||
{
|
||||
fn new_unit(interner: I) -> Self;
|
||||
|
||||
fn new_bool(interner: I) -> Self;
|
||||
|
||||
fn new_u8(interner: I) -> Self;
|
||||
|
||||
fn new_usize(interner: I) -> Self;
|
||||
|
||||
fn new_infer(interner: I, var: ty::InferTy) -> Self;
|
||||
|
||||
fn new_var(interner: I, var: ty::TyVid) -> Self;
|
||||
@ -107,6 +113,10 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||
matches!(self.kind(), ty::Infer(ty::TyVar(_)))
|
||||
}
|
||||
|
||||
fn is_fn_ptr(self) -> bool {
|
||||
matches!(self.kind(), ty::FnPtr(_))
|
||||
}
|
||||
|
||||
fn fn_sig(self, interner: I) -> ty::Binder<I, ty::FnSig<I>> {
|
||||
match self.kind() {
|
||||
ty::FnPtr(sig) => sig,
|
||||
@ -126,6 +136,49 @@ pub trait Ty<I: Interner<Ty = Self>>:
|
||||
_ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self),
|
||||
}
|
||||
}
|
||||
|
||||
fn discriminant_ty(self, interner: I) -> I::Ty;
|
||||
|
||||
fn async_destructor_ty(self, interner: I) -> I::Ty;
|
||||
|
||||
/// Returns `true` when the outermost type cannot be further normalized,
|
||||
/// resolved, or instantiated. This includes all primitive types, but also
|
||||
/// things like ADTs and trait objects, sice even if their arguments or
|
||||
/// nested types may be further simplified, the outermost [`ty::TyKind`] or
|
||||
/// type constructor remains the same.
|
||||
fn is_known_rigid(self) -> bool {
|
||||
match self.kind() {
|
||||
ty::Bool
|
||||
| ty::Char
|
||||
| ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Adt(_, _)
|
||||
| ty::Foreign(_)
|
||||
| ty::Str
|
||||
| ty::Array(_, _)
|
||||
| ty::Pat(_, _)
|
||||
| ty::Slice(_)
|
||||
| ty::RawPtr(_, _)
|
||||
| ty::Ref(_, _, _)
|
||||
| ty::FnDef(_, _)
|
||||
| ty::FnPtr(_)
|
||||
| ty::Dynamic(_, _, _)
|
||||
| ty::Closure(_, _)
|
||||
| ty::CoroutineClosure(_, _)
|
||||
| ty::Coroutine(_, _)
|
||||
| ty::CoroutineWitness(..)
|
||||
| ty::Never
|
||||
| ty::Tuple(_) => true,
|
||||
|
||||
ty::Error(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Alias(_, _)
|
||||
| ty::Param(_)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Placeholder(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Tys<I: Interner<Tys = Self>>:
|
||||
@ -200,6 +253,12 @@ pub trait Const<I: Interner<Const = Self>>:
|
||||
|
||||
fn new_expr(interner: I, expr: I::ExprConst) -> Self;
|
||||
|
||||
fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self;
|
||||
|
||||
fn new_error_with_message(interner: I, msg: impl ToString) -> Self {
|
||||
Self::new_error(interner, interner.delay_bug(msg))
|
||||
}
|
||||
|
||||
fn is_ct_var(self) -> bool {
|
||||
matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_)))
|
||||
}
|
||||
@ -221,6 +280,37 @@ pub trait GenericArg<I: Interner<GenericArg = Self>>:
|
||||
+ From<I::Region>
|
||||
+ From<I::Const>
|
||||
{
|
||||
fn as_type(&self) -> Option<I::Ty> {
|
||||
if let ty::GenericArgKind::Type(ty) = self.kind() { Some(ty) } else { None }
|
||||
}
|
||||
|
||||
fn expect_ty(&self) -> I::Ty {
|
||||
self.as_type().expect("expected a type")
|
||||
}
|
||||
|
||||
fn as_const(&self) -> Option<I::Const> {
|
||||
if let ty::GenericArgKind::Const(c) = self.kind() { Some(c) } else { None }
|
||||
}
|
||||
|
||||
fn expect_const(&self) -> I::Const {
|
||||
self.as_const().expect("expected a const")
|
||||
}
|
||||
|
||||
fn as_region(&self) -> Option<I::Region> {
|
||||
if let ty::GenericArgKind::Lifetime(c) = self.kind() { Some(c) } else { None }
|
||||
}
|
||||
|
||||
fn expect_region(&self) -> I::Region {
|
||||
self.as_region().expect("expected a const")
|
||||
}
|
||||
|
||||
fn is_non_region_infer(self) -> bool {
|
||||
match self.kind() {
|
||||
ty::GenericArgKind::Lifetime(_) => false,
|
||||
ty::GenericArgKind::Type(ty) => ty.is_ty_var(),
|
||||
ty::GenericArgKind::Const(ct) => ct.is_ct_var(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Term<I: Interner<Term = Self>>:
|
||||
@ -230,7 +320,7 @@ pub trait Term<I: Interner<Term = Self>>:
|
||||
if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None }
|
||||
}
|
||||
|
||||
fn expect_type(&self) -> I::Ty {
|
||||
fn expect_ty(&self) -> I::Ty {
|
||||
self.as_type().expect("expected a type, but found a const")
|
||||
}
|
||||
|
||||
@ -248,6 +338,19 @@ pub trait Term<I: Interner<Term = Self>>:
|
||||
ty::TermKind::Const(ct) => ct.is_ct_var(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_alias_term(self) -> Option<ty::AliasTerm<I>> {
|
||||
match self.kind() {
|
||||
ty::TermKind::Ty(ty) => match ty.kind() {
|
||||
ty::Alias(_kind, alias_ty) => Some(alias_ty.into()),
|
||||
_ => None,
|
||||
},
|
||||
ty::TermKind::Const(ct) => match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(uv) => Some(uv.into()),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
||||
@ -260,8 +363,19 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
|
||||
+ Default
|
||||
+ Relate<I>
|
||||
{
|
||||
fn rebase_onto(
|
||||
self,
|
||||
interner: I,
|
||||
source_def_id: I::DefId,
|
||||
target: I::GenericArgs,
|
||||
) -> I::GenericArgs;
|
||||
|
||||
fn type_at(self, i: usize) -> I::Ty;
|
||||
|
||||
fn region_at(self, i: usize) -> I::Region;
|
||||
|
||||
fn const_at(self, i: usize) -> I::Const;
|
||||
|
||||
fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs;
|
||||
|
||||
fn extend_with_error(
|
||||
@ -301,6 +415,9 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
|
||||
+ UpcastFrom<I, ty::NormalizesTo<I>>
|
||||
+ UpcastFrom<I, ty::TraitRef<I>>
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
|
||||
+ UpcastFrom<I, ty::TraitPredicate<I>>
|
||||
+ UpcastFrom<I, ty::OutlivesPredicate<I, I::Ty>>
|
||||
+ UpcastFrom<I, ty::OutlivesPredicate<I, I::Region>>
|
||||
+ IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
|
||||
{
|
||||
fn is_coinductive(self, interner: I) -> bool;
|
||||
@ -316,9 +433,34 @@ pub trait Clause<I: Interner<Clause = Self>>:
|
||||
+ Eq
|
||||
+ TypeFoldable<I>
|
||||
// FIXME: Remove these, uplift the `Upcast` impls.
|
||||
+ UpcastFrom<I, ty::TraitRef<I>>
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
|
||||
+ UpcastFrom<I, ty::ProjectionPredicate<I>>
|
||||
+ UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
|
||||
+ IntoKind<Kind = ty::Binder<I, ty::ClauseKind<I>>>
|
||||
{
|
||||
fn as_trait_clause(self) -> Option<ty::Binder<I, ty::TraitPredicate<I>>> {
|
||||
self.kind()
|
||||
.map_bound(|clause| {
|
||||
if let ty::ClauseKind::Trait(t) = clause {
|
||||
Some(t)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
fn as_projection_clause(self) -> Option<ty::Binder<I, ty::ProjectionPredicate<I>>> {
|
||||
self.kind()
|
||||
.map_bound(|clause| {
|
||||
if let ty::ClauseKind::Projection(p) = clause {
|
||||
Some(p)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
}
|
||||
|
||||
/// Common capabilities of placeholder kinds
|
||||
@ -350,16 +492,81 @@ pub trait ParamLike {
|
||||
pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
|
||||
fn def_id(self) -> I::DefId;
|
||||
|
||||
fn is_struct(self) -> bool;
|
||||
|
||||
/// Returns the type of the struct tail.
|
||||
///
|
||||
/// Expects the `AdtDef` to be a struct. If it is not, then this will panic.
|
||||
fn struct_tail_ty(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
|
||||
|
||||
fn is_phantom_data(self) -> bool;
|
||||
|
||||
// FIXME: perhaps use `all_fields` and expose `FieldDef`.
|
||||
fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl Iterator<Item = I::Ty>>;
|
||||
fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl IntoIterator<Item = I::Ty>>;
|
||||
|
||||
fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
|
||||
}
|
||||
|
||||
pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
|
||||
fn reveal(self) -> Reveal;
|
||||
|
||||
fn caller_bounds(self) -> impl IntoIterator<Item = I::Clause>;
|
||||
}
|
||||
|
||||
pub trait Features<I: Interner>: Copy {
|
||||
fn generic_const_exprs(self) -> bool;
|
||||
|
||||
fn coroutine_clone(self) -> bool;
|
||||
|
||||
fn associated_const_equality(self) -> bool;
|
||||
}
|
||||
|
||||
pub trait EvaluationCache<I: Interner> {
|
||||
/// Insert a final result into the global cache.
|
||||
fn insert(
|
||||
&self,
|
||||
tcx: I,
|
||||
key: CanonicalInput<I>,
|
||||
proof_tree: Option<I::CanonicalGoalEvaluationStepRef>,
|
||||
additional_depth: usize,
|
||||
encountered_overflow: bool,
|
||||
cycle_participants: FxHashSet<CanonicalInput<I>>,
|
||||
dep_node: I::DepNodeIndex,
|
||||
result: QueryResult<I>,
|
||||
);
|
||||
|
||||
/// Try to fetch a cached result, checking the recursion limit
|
||||
/// and handling root goals of coinductive cycles.
|
||||
///
|
||||
/// If this returns `Some` the cache result can be used.
|
||||
fn get(
|
||||
&self,
|
||||
tcx: I,
|
||||
key: CanonicalInput<I>,
|
||||
stack_entries: impl IntoIterator<Item = CanonicalInput<I>>,
|
||||
available_depth: usize,
|
||||
) -> Option<CacheData<I>>;
|
||||
}
|
||||
|
||||
pub trait DefId<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
|
||||
fn as_local(self) -> Option<I::LocalDefId>;
|
||||
}
|
||||
|
||||
pub trait BoundExistentialPredicates<I: Interner>:
|
||||
Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Relate<I>
|
||||
+ IntoIterator<Item = ty::Binder<I, ty::ExistentialPredicate<I>>>
|
||||
{
|
||||
fn principal_def_id(self) -> Option<I::DefId>;
|
||||
|
||||
fn principal(self) -> Option<ty::Binder<I, ty::ExistentialTraitRef<I>>>;
|
||||
|
||||
fn auto_traits(self) -> impl IntoIterator<Item = I::DefId>;
|
||||
|
||||
fn projection_bounds(
|
||||
self,
|
||||
) -> impl IntoIterator<Item = ty::Binder<I, ty::ExistentialProjection<I>>>;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use rustc_ast_ir::Movability;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use smallvec::SmallVec;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
@ -10,6 +11,7 @@ use crate::ir_print::IrPrint;
|
||||
use crate::lang_items::TraitSolverLangItem;
|
||||
use crate::relate::Relate;
|
||||
use crate::solve::inspect::CanonicalGoalEvaluationStep;
|
||||
use crate::solve::{ExternalConstraintsData, PredefinedOpaquesData, SolverMode};
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{self as ty};
|
||||
|
||||
@ -28,9 +30,8 @@ pub trait Interner:
|
||||
+ IrPrint<ty::CoercePredicate<Self>>
|
||||
+ IrPrint<ty::FnSig<Self>>
|
||||
{
|
||||
type DefId: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
|
||||
type DefId: DefId<Self>;
|
||||
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
|
||||
type AdtDef: AdtDef<Self>;
|
||||
|
||||
type GenericArgs: GenericArgs<Self>;
|
||||
type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>;
|
||||
@ -45,16 +46,53 @@ pub trait Interner:
|
||||
+ Default;
|
||||
type BoundVarKind: Copy + Debug + Hash + Eq;
|
||||
|
||||
type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = ty::CanonicalVarInfo<Self>>;
|
||||
type PredefinedOpaques: Copy + Debug + Hash + Eq;
|
||||
type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
|
||||
type ExternalConstraints: Copy + Debug + Hash + Eq;
|
||||
type PredefinedOpaques: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ TypeFoldable<Self>
|
||||
+ Deref<Target = PredefinedOpaquesData<Self>>;
|
||||
fn mk_predefined_opaques_in_body(
|
||||
self,
|
||||
data: PredefinedOpaquesData<Self>,
|
||||
) -> Self::PredefinedOpaques;
|
||||
|
||||
type DefiningOpaqueTypes: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Default
|
||||
+ Eq
|
||||
+ TypeVisitable<Self>
|
||||
+ Deref<Target: Deref<Target = [Self::LocalDefId]>>;
|
||||
type CanonicalGoalEvaluationStepRef: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Deref<Target = CanonicalGoalEvaluationStep<Self>>;
|
||||
|
||||
type CanonicalVars: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ IntoIterator<Item = ty::CanonicalVarInfo<Self>>
|
||||
+ Deref<Target: Deref<Target = [ty::CanonicalVarInfo<Self>]>>
|
||||
+ Default;
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
|
||||
|
||||
type ExternalConstraints: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ TypeFoldable<Self>
|
||||
+ Deref<Target = ExternalConstraintsData<Self>>;
|
||||
fn mk_external_constraints(
|
||||
self,
|
||||
data: ExternalConstraintsData<Self>,
|
||||
) -> Self::ExternalConstraints;
|
||||
|
||||
type DepNodeIndex;
|
||||
fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex);
|
||||
|
||||
// Kinds of tys
|
||||
type Ty: Ty<Self>;
|
||||
type Tys: Tys<Self>;
|
||||
@ -65,12 +103,7 @@ pub trait Interner:
|
||||
|
||||
// Things stored inside of tys
|
||||
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
|
||||
type BoundExistentialPredicates: Copy
|
||||
+ Debug
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ Relate<Self>
|
||||
+ IntoIterator<Item = ty::Binder<Self, ty::ExistentialPredicate<Self>>>;
|
||||
type BoundExistentialPredicates: BoundExistentialPredicates<Self>;
|
||||
type AllocId: Copy + Debug + Hash + Eq;
|
||||
type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
|
||||
type Safety: Safety<Self>;
|
||||
@ -92,14 +125,15 @@ pub trait Interner:
|
||||
type PlaceholderRegion: PlaceholderLike;
|
||||
|
||||
// Predicates
|
||||
type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable<Self>;
|
||||
type ParamEnv: ParamEnv<Self>;
|
||||
type Predicate: Predicate<Self>;
|
||||
type Clause: Clause<Self>;
|
||||
type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
|
||||
|
||||
fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
|
||||
type EvaluationCache: EvaluationCache<Self>;
|
||||
fn evaluation_cache(self, mode: SolverMode) -> Self::EvaluationCache;
|
||||
|
||||
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
|
||||
fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
|
||||
|
||||
type GenericsOf: GenericsOf<Self>;
|
||||
fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
|
||||
@ -111,9 +145,11 @@ pub trait Interner:
|
||||
+ IntoIterator<Item: Deref<Target = ty::Variance>>;
|
||||
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf;
|
||||
|
||||
// FIXME: Remove after uplifting `EarlyBinder`
|
||||
fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>;
|
||||
|
||||
type AdtDef: AdtDef<Self>;
|
||||
fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef;
|
||||
|
||||
fn alias_ty_kind(self, alias: ty::AliasTy<Self>) -> ty::AliasTyKind;
|
||||
|
||||
fn alias_term_kind(self, alias: ty::AliasTerm<Self>) -> ty::AliasTermKind;
|
||||
@ -131,6 +167,8 @@ pub trait Interner:
|
||||
I: Iterator<Item = T>,
|
||||
T: CollectAndApply<Self::GenericArg, Self::GenericArgs>;
|
||||
|
||||
fn check_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs) -> bool;
|
||||
|
||||
fn check_and_mk_args(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
@ -175,6 +213,17 @@ pub trait Interner:
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
|
||||
|
||||
fn predicates_of(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
|
||||
|
||||
fn own_predicates_of(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
|
||||
|
||||
// FIXME: Rename this so it's obvious it's only *immediate* super predicates.
|
||||
fn super_predicates_of(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
@ -184,7 +233,64 @@ pub trait Interner:
|
||||
|
||||
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId;
|
||||
|
||||
fn is_lang_item(self, def_id: Self::DefId, lang_item: TraitSolverLangItem) -> bool;
|
||||
|
||||
fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator<Item = Self::DefId>;
|
||||
|
||||
// FIXME: move `fast_reject` into `rustc_type_ir`.
|
||||
fn args_may_unify_deep(
|
||||
self,
|
||||
obligation_args: Self::GenericArgs,
|
||||
impl_args: Self::GenericArgs,
|
||||
) -> bool;
|
||||
|
||||
fn for_each_relevant_impl(
|
||||
self,
|
||||
trait_def_id: Self::DefId,
|
||||
self_ty: Self::Ty,
|
||||
f: impl FnMut(Self::DefId),
|
||||
);
|
||||
|
||||
fn has_item_definition(self, def_id: Self::DefId) -> bool;
|
||||
|
||||
fn impl_is_default(self, impl_def_id: Self::DefId) -> bool;
|
||||
|
||||
fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder<Self, ty::TraitRef<Self>>;
|
||||
|
||||
fn impl_polarity(self, impl_def_id: Self::DefId) -> ty::ImplPolarity;
|
||||
|
||||
fn trait_is_auto(self, trait_def_id: Self::DefId) -> bool;
|
||||
|
||||
fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool;
|
||||
|
||||
fn trait_is_object_safe(self, trait_def_id: Self::DefId) -> bool;
|
||||
|
||||
fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool;
|
||||
|
||||
fn fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option<ty::ClosureKind>;
|
||||
|
||||
fn async_fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option<ty::ClosureKind>;
|
||||
|
||||
fn supertrait_def_ids(self, trait_def_id: Self::DefId)
|
||||
-> impl IntoIterator<Item = Self::DefId>;
|
||||
|
||||
fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed;
|
||||
|
||||
fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool;
|
||||
fn coroutine_is_async(self, coroutine_def_id: Self::DefId) -> bool;
|
||||
fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool;
|
||||
fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool;
|
||||
|
||||
fn layout_is_pointer_like(self, param_env: Self::ParamEnv, ty: Self::Ty) -> bool;
|
||||
|
||||
type UnsizingParams: Deref<Target = BitSet<u32>>;
|
||||
fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
|
||||
|
||||
fn find_const_ty_from_env(
|
||||
self,
|
||||
param_env: Self::ParamEnv,
|
||||
placeholder: Self::PlaceholderConst,
|
||||
) -> Self::Ty;
|
||||
}
|
||||
|
||||
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
|
||||
|
@ -1,8 +1,36 @@
|
||||
/// Lang items used by the new trait solver. This can be mapped to whatever internal
|
||||
/// representation of `LangItem`s used in the underlying compiler implementation.
|
||||
pub enum TraitSolverLangItem {
|
||||
Future,
|
||||
FutureOutput,
|
||||
// tidy-alphabetical-start
|
||||
AsyncDestruct,
|
||||
AsyncFnKindHelper,
|
||||
AsyncFnKindUpvars,
|
||||
AsyncFnOnceOutput,
|
||||
AsyncIterator,
|
||||
CallOnceFuture,
|
||||
CallRefFuture,
|
||||
Clone,
|
||||
Copy,
|
||||
Coroutine,
|
||||
CoroutineReturn,
|
||||
CoroutineYield,
|
||||
Destruct,
|
||||
DiscriminantKind,
|
||||
DynMetadata,
|
||||
FnPtrTrait,
|
||||
FusedIterator,
|
||||
Future,
|
||||
FutureOutput,
|
||||
Iterator,
|
||||
Metadata,
|
||||
Option,
|
||||
PointeeTrait,
|
||||
PointerLike,
|
||||
Poll,
|
||||
Sized,
|
||||
TransmuteTrait,
|
||||
Tuple,
|
||||
Unpin,
|
||||
Unsize,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ mod canonical;
|
||||
mod const_kind;
|
||||
mod flags;
|
||||
mod generic_arg;
|
||||
mod infcx;
|
||||
mod interner;
|
||||
mod opaque_ty;
|
||||
mod predicate;
|
||||
@ -62,7 +61,6 @@ pub use codec::*;
|
||||
pub use const_kind::*;
|
||||
pub use flags::*;
|
||||
pub use generic_arg::*;
|
||||
pub use infcx::InferCtxtLike;
|
||||
pub use interner::*;
|
||||
pub use opaque_ty::*;
|
||||
pub use predicate::*;
|
||||
|
@ -7,7 +7,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen
|
||||
|
||||
use crate::inherent::*;
|
||||
use crate::lift::Lift;
|
||||
use crate::upcast::Upcast;
|
||||
use crate::upcast::{Upcast, UpcastFrom};
|
||||
use crate::visit::TypeVisitableExt as _;
|
||||
use crate::{self as ty, Interner};
|
||||
|
||||
@ -166,6 +166,12 @@ impl<I: Interner> ty::Binder<I, TraitPredicate<I>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> UpcastFrom<I, TraitRef<I>> for TraitPredicate<I> {
|
||||
fn upcast_from(from: TraitRef<I>, _tcx: I) -> Self {
|
||||
TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive }
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Interner> fmt::Debug for TraitPredicate<I> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// FIXME(effects) printing?
|
||||
|
@ -57,6 +57,19 @@ pub enum Reveal {
|
||||
All,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum SolverMode {
|
||||
/// Ordinary trait solving, using everywhere except for coherence.
|
||||
Normal,
|
||||
/// Trait solving during coherence. There are a few notable differences
|
||||
/// between coherence and ordinary trait solving.
|
||||
///
|
||||
/// Most importantly, trait solving during coherence must not be incomplete,
|
||||
/// i.e. return `Err(NoSolution)` for goals for which a solution exists.
|
||||
/// This means that we must not make any guesses or arbitrary choices.
|
||||
Coherence,
|
||||
}
|
||||
|
||||
pub type CanonicalInput<I, T = <I as Interner>::Predicate> = Canonical<I, QueryInput<I, T>>;
|
||||
pub type CanonicalResponse<I> = Canonical<I, Response<I>>;
|
||||
/// The result of evaluating a canonical query.
|
||||
@ -143,6 +156,22 @@ pub struct QueryInput<I: Interner, P> {
|
||||
pub predefined_opaques_in_body: I::PredefinedOpaques,
|
||||
}
|
||||
|
||||
/// Opaques that are defined in the inference context before a query is called.
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
Clone(bound = ""),
|
||||
Hash(bound = ""),
|
||||
PartialEq(bound = ""),
|
||||
Eq(bound = ""),
|
||||
Debug(bound = ""),
|
||||
Default(bound = "")
|
||||
)]
|
||||
#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
|
||||
#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
|
||||
pub struct PredefinedOpaquesData<I: Interner> {
|
||||
pub opaque_types: Vec<(ty::OpaqueTypeKey<I>, I::Ty)>,
|
||||
}
|
||||
|
||||
/// Possible ways the given goal can be proven.
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(
|
||||
@ -356,3 +385,12 @@ impl MaybeCause {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(derivative::Derivative)]
|
||||
#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
|
||||
pub struct CacheData<I: Interner> {
|
||||
pub result: QueryResult<I>,
|
||||
pub proof_tree: Option<I::CanonicalGoalEvaluationStepRef>,
|
||||
pub additional_depth: usize,
|
||||
pub encountered_overflow: bool,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user