diff --git a/Cargo.lock b/Cargo.lock index 2e10b4c49abc7..14ee031ad047e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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]] diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c908faec7560b..510e9a06dfb06 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -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>>, } -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 { - // 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 { - 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 { - // 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 { - 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 + Copy>( - &self, - value: ty::Binder<'tcx, T>, - ) -> T { - self.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - value, - ) - } - - fn enter_forall> + Copy, U>( - &self, - value: ty::Binder<'tcx, T>, - f: impl FnOnce(T) -> U, - ) -> U { - self.enter_forall(value, f) - } - - fn relate>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) - } - - fn eq_structurally_relating_aliases>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases_no_trace(lhs, rhs) - } - - fn resolve_vars_if_possible(&self, value: T) -> T - where - T: TypeFoldable>, - { - self.resolve_vars_if_possible(value) - } - - fn probe(&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 { + self.defining_opaque_types + } + pub fn next_trait_solver(&self) -> bool { self.next_trait_solver } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 3d4e5caa9b27c..e3d7dff3c66bb 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -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>, - [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>, + [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem, [] mod_child: rustc_middle::metadata::ModChild, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 9e979620a440e..90f80f90767d9 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -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, P>; pub type QueryInput<'tcx, P> = ir::solve::QueryInput, P>; @@ -19,17 +19,11 @@ pub type CandidateSource<'tcx> = ir::solve::CandidateSource>; pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput, P>; pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse>; -/// 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>>); impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { - type Target = PredefinedOpaquesData<'tcx>; + type Target = PredefinedOpaquesData>; fn deref(&self) -> &Self::Target { &self.0 diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs index dc31114b2c459..72a8d4eb4050c 100644 --- a/compiler/rustc_middle/src/traits/solve/cache.rs +++ b/compiler/rustc_middle/src/traits/solve/cache.rs @@ -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, CacheEntry<'tcx>>>, } -#[derive(Debug, PartialEq, Eq)] -pub struct CacheData<'tcx> { - pub result: QueryResult<'tcx>, - pub proof_tree: Option<&'tcx inspect::CanonicalGoalEvaluationStep>>, - pub additional_depth: usize, - pub encountered_overflow: bool, -} - -impl<'tcx> EvaluationCache<'tcx> { +impl<'tcx> rustc_type_ir::inherent::EvaluationCache> 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>, - available_depth: Limit, - ) -> Option> { + available_depth: usize, + ) -> Option>> { 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, } }) diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 684b3233cfd61..8e221cdc603ba 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -205,6 +205,14 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { self.did() } + fn is_struct(self) -> bool { + self.is_struct() + } + + fn struct_tail_ty(self, interner: TyCtxt<'tcx>) -> Option>> { + 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> for AdtDef<'tcx> { fn all_field_tys( self, tcx: TyCtxt<'tcx>, - ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { ty::EarlyBinder::bind( self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()), ) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 12f0c38b054a0..32d01d07c17e7 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -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>; @@ -176,6 +176,10 @@ impl<'tcx> rustc_type_ir::inherent::Const> 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> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7a804c236387d..6d64c1d50aea3 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -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; - 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::PredefinedOpaques { + self.mk_predefined_opaques_in_body(data) + } type DefiningOpaqueTypes = &'tcx ty::List; - type ExternalConstraints = ExternalConstraints<'tcx>; type CanonicalGoalEvaluationStepRef = &'tcx solve::inspect::CanonicalGoalEvaluationStep>; + type CanonicalVars = CanonicalVarInfos<'tcx>; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { + self.mk_canonical_var_infos(infos) + } + type ExternalConstraints = ExternalConstraints<'tcx>; + fn mk_external_constraints( + self, + data: ExternalConstraintsData, + ) -> ExternalConstraints<'tcx> { + self.mk_external_constraints(data) + } + type DepNodeIndex = DepNodeIndex; + fn with_cached_task(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>; + 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>; - 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>>(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::CanonicalVars { - self.mk_canonical_var_infos(infos) + fn expand_abstract_consts>>(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::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(self, args: I) -> T::Output where I: Iterator, - T: CollectAndApply, + T: CollectAndApply>, { 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(self, args: I) -> T::Output where I: Iterator, - T: CollectAndApply, + T: CollectAndApply, &'tcx List>>, { 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>> { + 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>> { + 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 { @@ -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 { + self.fn_trait_kind_from_def_id(trait_def_id) + } + + fn async_fn_trait_kind_from_def_id(self, trait_def_id: DefId) -> Option { + self.async_fn_trait_kind_from_def_id(trait_def_id) + } + + fn supertrait_def_ids(self, trait_def_id: DefId) -> impl IntoIterator { + 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; + 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> for DefId { + fn as_local(self) -> Option { + self.as_local() + } } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { @@ -358,6 +658,10 @@ impl<'tcx> rustc_type_ir::inherent::Features> 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, ()>; @@ -386,7 +690,7 @@ pub struct CtxtInterners<'tcx> { layout: InternedSet<'tcx, LayoutS>, adt_def: InternedSet<'tcx, AdtDefData>, external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, - predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, + predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, 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>): 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>): PredefinedOpaques -> PredefinedOpaques<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 54c88e48614b0..83d45ca78d9d9 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -44,10 +44,27 @@ pub struct GenericArg<'tcx> { impl<'tcx> rustc_type_ir::inherent::GenericArg> for GenericArg<'tcx> {} impl<'tcx> rustc_type_ir::inherent::GenericArgs> 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(), } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 185dbe4473581..6467689a8aa15 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -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, Span)> { + EarlyBinder::bind(self.predicates).instantiate_identity_iter_copied() + } + #[instrument(level = "debug", skip(self, tcx))] fn instantiate_into( &self, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d07541bad93d2..9c2bfc12a18a1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -990,6 +990,16 @@ pub struct ParamEnv<'tcx> { packed: CopyTaggedPtr, ParamTag, true>, } +impl<'tcx> rustc_type_ir::inherent::ParamEnv> for ParamEnv<'tcx> { + fn reveal(self) -> Reveal { + self.reveal() + } + + fn caller_bounds(self) -> impl IntoIterator> { + self.caller_bounds() + } +} + #[derive(Copy, Clone)] struct ParamTag { reveal: traits::Reveal, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index ae36f2624ca5f..e9b37503bb3e5 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -175,6 +175,14 @@ pub struct Clause<'tcx>( impl<'tcx> rustc_type_ir::inherent::Clause> 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> + for &'tcx ty::List> +{ + fn principal_def_id(self) -> Option { + self.principal_def_id() + } + + fn principal(self) -> Option> { + self.principal() + } + + fn auto_traits(self) -> impl IntoIterator { + self.auto_traits() + } + + fn projection_bounds( + self, + ) -> impl IntoIterator>> { + self.projection_bounds() + } +} + impl<'tcx> ty::List> { /// Returns the "principal `DefId`" of this set of existential predicates. /// @@ -481,12 +511,6 @@ impl<'tcx> UpcastFrom, TraitRef<'tcx>> for Predicate<'tcx> { } } -impl<'tcx> UpcastFrom, 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, 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, PolyTraitPredicate<'tcx>> for Clause<'tcx> { } } +impl<'tcx> UpcastFrom, 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, 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) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8308e537e5edf..9c8a3484aa5bd 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -930,6 +930,22 @@ impl<'tcx> rustc_type_ir::inherent::Ty> 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 diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 52a0e72e17e28..b079ed521d34c 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -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`. diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 50dbc991f8fd9..3a5f438b4325d 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -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", +] diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index f22e24ef6541a..a81fd03d034f7 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -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, I: Interner> { +pub struct Canonicalizer<'a, Infcx: SolverDelegate, I: Interner> { infcx: &'a Infcx, canonicalize_mode: CanonicalizeMode, @@ -46,7 +47,7 @@ pub struct Canonicalizer<'a, Infcx: InferCtxtLike, I: Interner> { binder_index: ty::DebruijnIndex, } -impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infcx, I> { +impl<'a, Infcx: SolverDelegate, I: Interner> Canonicalizer<'a, Infcx, I> { pub fn canonicalize>( infcx: &'a Infcx, canonicalize_mode: CanonicalizeMode, @@ -210,7 +211,7 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> Canonicalizer<'a, Infc } } -impl, I: Interner> TypeFolder +impl, I: Interner> TypeFolder for Canonicalizer<'_, Infcx, I> { fn interner(&self) -> I { diff --git a/compiler/rustc_next_trait_solver/src/infcx.rs b/compiler/rustc_next_trait_solver/src/infcx.rs new file mode 100644 index 0000000000000..c249eb94cf654 --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/infcx.rs @@ -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( + interner: Self::Interner, + solver_mode: SolverMode, + canonical: &ty::Canonical, + ) -> (Self, V, ty::CanonicalVarValues) + where + V: TypeFoldable; + + fn universe(&self) -> ty::UniverseIndex; + fn create_next_universe(&self) -> ty::UniverseIndex; + + fn universe_of_ty(&self, ty: ty::TyVid) -> Option; + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; + + 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) -> ::Ty; + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; + fn opportunistic_resolve_float_var( + &self, + vid: ty::FloatVid, + ) -> ::Ty; + fn opportunistic_resolve_ct_var( + &self, + vid: ty::ConstVid, + ) -> ::Const; + fn opportunistic_resolve_effect_var( + &self, + vid: ty::EffectVid, + ) -> ::Const; + fn opportunistic_resolve_lt_var( + &self, + vid: ty::RegionVid, + ) -> ::Region; + + fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; + + fn next_ty_infer(&self) -> ::Ty; + fn next_const_infer(&self) -> ::Const; + fn fresh_args_for_item( + &self, + def_id: ::DefId, + ) -> ::GenericArgs; + + fn fresh_var_for_kind_with_span( + &self, + arg: ::GenericArg, + span: Self::Span, + ) -> ::GenericArg; + + fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder, + ) -> T; + + fn enter_forall + Copy, U>( + &self, + value: ty::Binder, + f: impl FnOnce(T) -> U, + ) -> U; + + fn relate>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable; + + fn probe(&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>, + ) -> impl Iterator>>; + + fn try_const_eval_resolve( + &self, + param_env: ::ParamEnv, + unevaluated: ty::UnevaluatedConst, + ) -> Option<::Const>; + + fn sub_regions( + &self, + sub: ::Region, + sup: ::Region, + ); + + fn register_ty_outlives( + &self, + ty: ::Ty, + r: ::Region, + ); + + // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`! + fn well_formed_goals( + &self, + param_env: ::ParamEnv, + arg: ::GenericArg, + ) -> Option::Predicate>>>; + + fn clone_opaque_types_for_query_response( + &self, + ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; + + fn make_deduplicated_outlives_constraints( + &self, + ) -> Vec::GenericArg>>; + + fn instantiate_canonical( + &self, + canonical: ty::Canonical, + values: ty::CanonicalVarValues, + ) -> V + where + V: TypeFoldable; + + fn instantiate_canonical_var_with_infer( + &self, + cv_info: ty::CanonicalVarInfo, + universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, + ) -> ::GenericArg; + + // FIXME: Can we implement this in terms of `add` and `inject`? + fn insert_hidden_type( + &self, + opaque_type_key: ty::OpaqueTypeKey, + param_env: ::ParamEnv, + hidden_ty: ::Ty, + goals: &mut Vec::Predicate>>, + ) -> Result<(), NoSolution>; + + fn add_item_bounds_for_hidden_type( + &self, + def_id: ::DefId, + args: ::GenericArgs, + param_env: ::ParamEnv, + hidden_ty: ::Ty, + goals: &mut Vec::Predicate>>, + ); + + fn inject_new_hidden_type_unchecked( + &self, + key: ty::OpaqueTypeKey, + hidden_ty: ::Ty, + ); + + fn reset_opaque_types(&self); + + fn trait_ref_is_knowable( + &self, + trait_ref: ty::TraitRef, + lazily_normalize_ty: impl FnMut( + ::Ty, + ) -> Result<::Ty, E>, + ) -> Result; + + fn fetch_eligible_assoc_item( + &self, + param_env: ::ParamEnv, + goal_trait_ref: ty::TraitRef, + trait_assoc_def_id: ::DefId, + impl_def_id: ::DefId, + ) -> Result::DefId>, NoSolution>; + + fn is_transmutable( + &self, + param_env: ::ParamEnv, + dst: ::Ty, + src: ::Ty, + assume: ::Const, + ) -> Result; +} diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index 144caf36ee538..79c6925221e14 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -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; diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 5c00b6978d695..3d8d957eaae4f 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -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 = ::Interner> +pub struct EagerResolver<'a, Infcx, I = ::Interner> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, 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, I: Interner> TypeFolder for EagerResolver<'_, Infcx> { +impl, I: Interner> TypeFolder for EagerResolver<'_, Infcx> { fn interner(&self) -> I { self.infcx.interner() } diff --git a/compiler/rustc_next_trait_solver/src/solve.rs b/compiler/rustc_next_trait_solver/src/solve.rs deleted file mode 100644 index eba96facabc63..0000000000000 --- a/compiler/rustc_next_trait_solver/src/solve.rs +++ /dev/null @@ -1 +0,0 @@ -pub use rustc_type_ir::solve::*; diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs similarity index 89% rename from compiler/rustc_trait_selection/src/solve/alias_relate.rs rename to compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index 4e52caa5a5b8e..fbc8ac1d5d5c5 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + 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, + ) -> QueryResult { 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()); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs similarity index 59% rename from compiler/rustc_trait_selection/src/solve/assembly/mod.rs rename to compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 1cdbf0820780d..9a1537d260608 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -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 { pub(super) source: CandidateSource, @@ -35,39 +28,42 @@ pub(super) struct Candidate { } /// Methods used to assemble candidates for either trait or projection goals. -pub(super) trait GoalKind<'tcx>: - TypeFoldable> + Copy + Eq + std::fmt::Display +pub(super) trait GoalKind::Interner>: + TypeFoldable + Copy + Eq + std::fmt::Display +where + Infcx: SolverDelegate, + 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; - 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>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource, + goal: Goal, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + ) -> Result, 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>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - requirements: impl IntoIterator>)>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + parent_source: CandidateSource, + goal: Goal, + assumption: I::Clause, + requirements: impl IntoIterator)>, + ) -> Result, 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>, - goal: Goal<'tcx, Self>, - assumption: ty::Clause<'tcx>, - ) -> Result>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource, + goal: Goal, + assumption: I::Clause, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + impl_def_id: I::DefId, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + guar: I::ErrorGuaranteed, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn` /// 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, kind: ty::ClosureKind, - ) -> Result>, NoSolution>; + ) -> Result, NoSolution>; /// An async closure is known to implement the `AsyncFn` 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, kind: ty::ClosureKind, - ) -> Result>, NoSolution>; + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A coroutine (that comes from an `async` desugaring) is known to implement /// `Future`, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A coroutine (that comes from a `gen` desugaring) is known to implement /// `Iterator`, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_async_iterator_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; /// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to /// implement `Coroutine`, 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>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_discriminant_kind_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_async_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_destruct_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution>; fn consider_builtin_transmute_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, NoSolution>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>>; + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Vec>; } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn assemble_and_evaluate_candidates>( +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ + pub(super) fn assemble_and_evaluate_candidates>( &mut self, - goal: Goal<'tcx, G>, - ) -> Vec>> { + goal: Goal, + ) -> Vec> { 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 = 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>, NoSolution> { + ) -> Result, 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>( + fn assemble_impl_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { 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) => (), - } - } - } - }; - - 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); + 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; } - } - 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); + match G::consider_impl_candidate(self, goal, impl_def_id) { + Ok(candidate) => candidates.push(candidate), + Err(NoSolution) => (), } - } - - // 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>( - &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, - ) { - 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>( + fn assemble_builtin_impl_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { 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 + Bar` and `dyn Foo: Unsize>` - 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>( + fn assemble_param_env_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { - 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>( + fn assemble_alias_bound_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { 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>( + fn assemble_alias_bound_candidates_recur>( &mut self, - self_ty: Ty<'tcx>, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + self_ty: I::Ty, + goal: Goal, + candidates: &mut Vec>, ) { - 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>( + fn assemble_object_bound_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { 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>( + fn assemble_coherence_unknowable_candidates>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { 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>( + fn discard_impls_shadowed_by_env>( &mut self, - goal: Goal<'tcx, G>, - candidates: &mut Vec>>, + goal: Goal, + candidates: &mut Vec>, ) { let tcx = self.interner(); - let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = + let trait_goal: Goal> = 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>>, - ) -> QueryResult<'tcx> { + pub(super) fn merge_candidates(&mut self, candidates: Vec>) -> QueryResult { // First try merging all candidates. This is complete and fully sound. let responses = candidates.iter().map(|c| c.result).collect::>(); if let Some(result) = self.try_merge_responses(&responses) { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs similarity index 97% rename from compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs rename to compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index d6074617cafe7..202af76565a88 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -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( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, ) -> Result>, NoSolution> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { let tcx = ecx.interner(); @@ -108,7 +106,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait( ty: I::Ty, ) -> Result>, NoSolution> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { match ty.kind() { @@ -176,7 +174,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait Result>, NoSolution> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { match ty.kind() { @@ -663,7 +661,7 @@ pub(in crate::solve) fn predicates_for_object_candidate( object_bounds: I::BoundExistentialPredicates, ) -> Vec> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { let tcx = ecx.interner(); @@ -712,14 +710,14 @@ where .collect() } -struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike, I: Interner> { +struct ReplaceProjectionWith<'a, Infcx: SolverDelegate, I: Interner> { ecx: &'a EvalCtxt<'a, Infcx>, param_env: I::ParamEnv, mapping: FxHashMap>>, nested: Vec>, } -impl, I: Interner> TypeFolder +impl, I: Interner> TypeFolder for ReplaceProjectionWith<'_, Infcx, I> { fn interner(&self) -> I { @@ -744,7 +742,7 @@ impl, I: Interner> TypeFolder ) .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) } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs similarity index 65% rename from compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs rename to compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index b5753d60f5993..c6611285a3bed 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -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 std::iter; + +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::{ - 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, + response_no_constraints_raw, CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, + ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution, + PredefinedOpaquesData, QueryInput, QueryResult, Response, }; -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>; +trait ResponseT { + fn var_values(&self) -> CanonicalVarValues; } -impl<'tcx> ResponseT<'tcx> for Response> { - fn var_values(&self) -> CanonicalVarValues> { +impl ResponseT for Response { + fn var_values(&self) -> CanonicalVarValues { self.var_values } } -impl<'tcx, T> ResponseT<'tcx> for inspect::State, T> { - fn var_values(&self) -> CanonicalVarValues> { +impl ResponseT for inspect::State { + fn var_values(&self) -> CanonicalVarValues { self.var_values } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ /// Canonicalizes the goal remembering the original values /// for each bound variable. - pub(super) fn canonicalize_goal>>( + pub(super) fn canonicalize_goal>( &self, - goal: Goal<'tcx, T>, - ) -> (Vec>, CanonicalInput<'tcx, T>) { + goal: Goal, + ) -> (Vec, CanonicalInput) { 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 { 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 { 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>, - ) -> ExternalConstraintsData> { + normalization_nested_goals: NestedNormalizationGoals, + ) -> ExternalConstraintsData { // 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>, - response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals>, Certainty) { + param_env: I::ParamEnv, + original_values: Vec, + response: CanonicalResponse, + ) -> (NestedNormalizationGoals, 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>( - infcx: &InferCtxt<'tcx>, - original_values: &[ty::GenericArg<'tcx>], - response: &Canonical<'tcx, T>, - ) -> CanonicalVarValues> { + fn compute_query_response_instantiation_values>( + infcx: &Infcx, + original_values: &[I::GenericArg], + response: &Canonical, + ) -> CanonicalVarValues { // 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>, + infcx: &Infcx, + param_env: I::ParamEnv, + original_values: &[I::GenericArg], + var_values: CanonicalVarValues, ) { 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], ) { 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::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( data: T, ) -> inspect::CanonicalState where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, T: TypeFoldable, { @@ -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>>( - infcx: &InferCtxt<'tcx>, - span: Span, - param_env: ty::ParamEnv<'tcx>, - orig_values: &mut Vec>, - state: inspect::CanonicalState, T>, -) -> T { +// FIXME: needs to be pub to be accessed by downstream +// `rustc_trait_selection::solve::inspect::analyse`. +pub fn instantiate_canonical_state>( + infcx: &Infcx, + span: Infcx::Span, + param_env: I::ParamEnv, + orig_values: &mut Vec, + state: inspect::CanonicalState, +) -> T +where + Infcx: SolverDelegate, + 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 diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs similarity index 78% rename from compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs rename to compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 74938d2bbd708..485758b91a285 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1,41 +1,30 @@ +use std::ops::ControlFlow; + 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_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, TypeVisitor}; -use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; +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 std::ops::ControlFlow; - -use crate::traits::coherence; - -use super::inspect::ProofTreeBuilder; -use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; -use super::{search_graph::SearchGraph, Goal}; -use super::{GoalSource, SolverMode}; +use tracing::{instrument, trace}; + +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 = ::Interner> +pub struct EvalCtxt<'a, Infcx, I = ::Interner> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { /// The inference context that backs (mostly) inference and placeholder terms @@ -112,9 +101,9 @@ pub struct NestedGoals { /// /// Forgetting to replace the RHS with a fresh inference variable when we evaluate /// this goal results in an ICE.. - pub normalizes_to_goals: Vec>>, + pub normalizes_to_goals: Vec>>, /// The rest of the goals which have not yet processed or remain ambiguous. - pub goals: Vec<(GoalSource, ir::solve::Goal)>, + pub goals: Vec<(GoalSource, Goal)>, } impl NestedGoals { @@ -127,14 +116,36 @@ impl NestedGoals { } } -#[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::Predicate>, + generate_proof_tree: GenerateProofTree, + ) -> (Result<(bool, Certainty), NoSolution>, Option>); + + // 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::Predicate>, + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Option>, + ); +} + +impl SolverDelegateEvalExt for Infcx +where + Infcx: SolverDelegate, + 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, generate_proof_tree: GenerateProofTree, - ) -> (Result<(bool, Certainty), NoSolution>, Option>>) - { + ) -> (Result<(bool, Certainty), NoSolution>, Option>) { 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, + generate_proof_tree: GenerateProofTree, + ) -> ( + Result<(NestedNormalizationGoals, bool, Certainty), NoSolution>, + Option>, + ) { + 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, + 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( - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, generate_proof_tree: GenerateProofTree, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> R, - ) -> (R, Option>>) { - 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>) { + 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( - tcx: TyCtxt<'tcx>, - search_graph: &'a mut search_graph::SearchGraph>, - canonical_input: CanonicalInput<'tcx>, - canonical_goal_evaluation: &mut ProofTreeBuilder>, - f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, + tcx: I, + search_graph: &'a mut search_graph::SearchGraph, + canonical_input: CanonicalInput, + canonical_goal_evaluation: &mut ProofTreeBuilder, + f: impl FnOnce(&mut EvalCtxt<'_, Infcx>, Goal) -> 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>, - canonical_input: CanonicalInput<'tcx>, - goal_evaluation: &mut ProofTreeBuilder>, - ) -> QueryResult<'tcx> { + tcx: I, + search_graph: &'a mut search_graph::SearchGraph, + canonical_input: CanonicalInput, + goal_evaluation: &mut ProofTreeBuilder, + ) -> QueryResult { 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, ) -> 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>, bool, Certainty), NoSolution> { + goal: Goal, + ) -> Result<(NestedNormalizationGoals, 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>, - response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals>, Certainty, bool) { + param_env: I::ParamEnv, + original_values: Vec, + response: CanonicalResponse, + ) -> (NestedNormalizationGoals, 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) -> QueryResult { 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, 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>, - ) { + pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal>) { goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); @@ -588,11 +603,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { } #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal( - &mut self, - source: GoalSource, - mut goal: ir::solve::Goal, - ) { + pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal) { goal.predicate = goal .predicate .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); @@ -604,7 +615,7 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn add_goals( &mut self, source: GoalSource, - goals: impl IntoIterator>, + goals: impl IntoIterator>, ) { for goal in goals { self.add_goal(source, goal); @@ -627,8 +638,8 @@ impl, 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, 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>, - ) -> bool { + pub(super) fn term_is_fully_unconstrained(&self, goal: Goal>) -> 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, I: Interner> EvalCtxt<'_, Infcx> { } }; - struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike, I: Interner> { + struct ContainsTermOrNotNameable<'a, Infcx: SolverDelegate, I: Interner> { term: I::Term, - universe_of_term: ir::UniverseIndex, + universe_of_term: ty::UniverseIndex, infcx: &'a Infcx, } - impl, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { - fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> { + impl, 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, I: Interner> EvalCtxt<'_, Infcx> { } } - impl, I: Interner> TypeVisitor + impl, I: Interner> TypeVisitor 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, 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, 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, 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, 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, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn relate_rigid_alias_non_alias( &mut self, param_env: I::ParamEnv, - alias: ir::AliasTerm, - variance: ir::Variance, + alias: ty::AliasTerm, + variance: ty::Variance, term: I::Term, ) -> Result<(), NoSolution> { // NOTE: this check is purely an optimization, the structural eq would @@ -770,7 +778,7 @@ impl, 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, 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, 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, I: Interner> EvalCtxt<'_, Infcx> { param_env: I::ParamEnv, lhs: T, rhs: T, - ) -> Result>, NoSolution> { - self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs) + ) -> Result>, NoSolution> { + self.infcx.relate(param_env, lhs, ty::Variance::Invariant, rhs) } pub(super) fn instantiate_binder_with_infer + Copy>( &self, - value: ir::Binder, + value: ty::Binder, ) -> T { self.infcx.instantiate_binder_with_infer(value) } pub(super) fn enter_forall + Copy, U>( &self, - value: ir::Binder, + value: ty::Binder, f: impl FnOnce(T) -> U, ) -> U { self.infcx.enter_forall(value, f) @@ -863,89 +871,72 @@ impl, 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>>> { - 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 { - 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>> { + 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, ) -> Result { 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) -> 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, + trait_assoc_def_id: I::DefId, + impl_def_id: I::DefId, + ) -> Result, 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, + 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> { + param_env: I::ParamEnv, + key: ty::OpaqueTypeKey, + ty: I::Ty, + ) -> Vec> { // 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> { - 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, + ) -> Option { + 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 { + 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, + Infcx: SolverDelegate, I: Interner, { ecx: &'me mut EvalCtxt<'a, Infcx>, @@ -1039,7 +1027,7 @@ where impl TypeFolder for ReplaceAliasWithInfer<'_, '_, Infcx, I> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, 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 } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs similarity index 89% rename from compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs rename to compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index ad6fdd2707de2..1c5358b3edb4d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -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, + Infcx: SolverDelegate, I: Interner, { ecx: &'me mut EvalCtxt<'a, Infcx, I>, @@ -20,7 +21,7 @@ where impl ProbeCtxt<'_, '_, Infcx, I, F, T> where F: FnOnce(&T) -> inspect::ProbeKind, - Infcx: InferCtxtLike, + Infcx: SolverDelegate, 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, + Infcx: SolverDelegate, I: Interner, { cx: ProbeCtxt<'me, 'a, Infcx, I, F, QueryResult>, @@ -65,7 +66,7 @@ where impl TraitProbeCtxt<'_, '_, Infcx, I, F> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, F: FnOnce(&QueryResult) -> inspect::ProbeKind, { @@ -80,7 +81,7 @@ where impl<'a, Infcx, I> EvalCtxt<'a, Infcx, I> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { /// `probe_kind` is only called when proof tree building is enabled so it can be diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs similarity index 95% rename from compiler/rustc_trait_selection/src/solve/inspect/build.rs rename to compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 35750598bc740..5fbec4b28d434 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -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::Interner> +pub(in crate::solve) struct ProofTreeBuilder::Interner> where - Infcx: InferCtxtLike, + Infcx: SolverDelegate, I: Interner, { _infcx: PhantomData, @@ -170,7 +173,7 @@ impl WipCanonicalGoalEvaluationStep { 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 WipProbeStep { } } -impl, I: Interner> ProofTreeBuilder { +impl, I: Interner> ProofTreeBuilder { fn new(state: impl Into>) -> ProofTreeBuilder { ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } } @@ -293,15 +296,15 @@ impl, I: Interner> ProofTreeBuilder { &mut self, goal: Goal, orig_values: &[I::GenericArg], - kind: solve::GoalEvaluationKind, + kind: GoalEvaluationKind, ) -> ProofTreeBuilder { 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, I: Interner> ProofTreeBuilder { 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, I: Interner> ProofTreeBuilder { })); 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, I: Interner> ProofTreeBuilder { let prev = state.current_evaluation_scope().kind.replace(probe_kind); assert_eq!(prev, None); } - _ => bug!(), + _ => panic!(), } } @@ -458,7 +461,7 @@ impl, I: Interner> ProofTreeBuilder { let prev = state.current_evaluation_scope().final_state.replace(final_state); assert_eq!(prev, None); } - _ => bug!(), + _ => panic!(), } } @@ -494,7 +497,7 @@ impl, I: Interner> ProofTreeBuilder { ); state.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal)) } - _ => bug!(), + _ => panic!(), } } @@ -518,7 +521,7 @@ impl, I: Interner> ProofTreeBuilder { .push(WipProbeStep::RecordImplArgs { impl_args }); } None => {} - _ => bug!(), + _ => panic!(), } } @@ -531,7 +534,7 @@ impl, I: Interner> ProofTreeBuilder { .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); } None => {} - _ => bug!(), + _ => panic!(), } } @@ -544,7 +547,7 @@ impl, I: Interner> ProofTreeBuilder { state.var_values.truncate(num_var_values); state.probe_depth -= 1; } - _ => bug!(), + _ => panic!(), } self diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs new file mode 100644 index 0000000000000..0d8c00601269b --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/mod.rs @@ -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; diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs similarity index 72% rename from compiler/rustc_trait_selection/src/solve/mod.rs rename to compiler/rustc_next_trait_solver/src/solve/mod.rs index 4f1be5cbc8532..02069016c2bde 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -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>> { - 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( + response: ty::Canonical>, +) -> 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, + I: Interner, +{ #[instrument(level = "trace", skip(self))] fn compute_type_outlives_goal( &mut self, - goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { 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>, + ) -> QueryResult { 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>) -> QueryResult { 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>) -> QueryResult { 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 { + 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) -> QueryResult { 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, + ) -> QueryResult { 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, + ) -> QueryResult { 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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + 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> { + responses: &[CanonicalResponse], + ) -> Option> { 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]) -> QueryResult { 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, NoSolution> { + param_env: I::ParamEnv, + ty: I::Ty, + ) -> Result { 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( + tcx: I, + max_universe: ty::UniverseIndex, + variables: I::CanonicalVars, certainty: Certainty, -) -> CanonicalResponse<'tcx> { - Canonical { +) -> CanonicalResponse { + 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()), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs similarity index 64% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs index a6e4b6ff4a81d..0f1c1f13c165e 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/anon_const.rs @@ -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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + 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>, + ) -> QueryResult { 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), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs similarity index 75% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 41b2b9cd4d260..8436f3ad48417 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ pub(super) fn normalize_inherent_associated_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { 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) } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs similarity index 63% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 5c5923e9d3964..ebc83bef5137b 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + 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>, + ) -> QueryResult { 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>) -> QueryResult { 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>, + 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 assembly::GoalKind for NormalizesTo +where + Infcx: SolverDelegate, + 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 { 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource, + goal: Goal, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal>, + impl_def_id: I::DefId, + ) -> Result, 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 ` as Trait>::Assoc` // - the applicable impl `impl Trait for Vec` @@ -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)?; - - if !tcx.check_args_compatible(assoc_def.item.def_id, associated_item_args) { - return error_response( - ecx, - "associated item has mismatched generic item arguments", - ); + let target_args = ecx.translate_args( + goal, + impl_def_id, + impl_args, + impl_trait_ref, + target_container_def_id, + )?; + + 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>, NoSolution> { + _ecx: &mut EvalCtxt<'_, Infcx>, + _guar: I::ErrorGuaranteed, + ) -> Result, NoSolution> { Err(NoSolution) } fn consider_auto_trait_candidate( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Result>, 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, + ) -> Result, 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>, NoSolution> { - bug!("trait aliases do not have associated types: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { - bug!("`Sized` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { - bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { - bug!("`PointerLike` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { - bug!("`FnPtr` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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, goal_kind: ty::ClosureKind, - ) -> Result>, NoSolution> { + ) -> Result, 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, goal_kind: ty::ClosureKind, - ) -> Result>, NoSolution> { + ) -> Result, 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) { + } 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(), LangItem::AsyncFnOnceOutput) - { + } else if tcx.is_lang_item( + goal.predicate.def_id(), + TraitSolverLangItem::AsyncFnOnceOutput, + ) { ( 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(), ], ), 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { - bug!("`Tuple` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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` 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 `::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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { - bug!("`FusedIterator` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>`. 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>> { - bug!("`Unsize` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Vec> { + 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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 `::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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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 `::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>, NoSolution> { - bug!("`Destruct` does not have an associated type: {:?}", goal); + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { - bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) + _ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, NoSolution> { + panic!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal) } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { +impl EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + 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>, - ) -> Result, NoSolution> { + goal: Goal>, + impl_def_id: I::DefId, + impl_args: I::GenericArgs, + impl_trait_ref: rustc_type_ir::TraitRef, + target_container_def_id: I::DefId, + ) -> Result { 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) - } - } - }) - } - - /// 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, 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 + 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 { - // 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) } + 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) + }) } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs similarity index 64% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 82464470b2a29..710671b45d0e7 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ pub(super) fn normalize_opaque_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { 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( + _interner: I, + args: I::GenericArgs, +) -> Result<(), NotUniqueParam> { + 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 { + DuplicateParam(I::GenericArg), + NotParam(I::GenericArg), +} diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs similarity index 67% rename from compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs rename to compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs index 5442b9ccffc87..45341917bb24b 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs @@ -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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + I: Interner, +{ pub(super) fn normalize_weak_type( &mut self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, - ) -> QueryResult<'tcx> { + goal: Goal>, + ) -> QueryResult { 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) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs similarity index 61% rename from compiler/rustc_trait_selection/src/solve/project_goals.rs rename to compiler/rustc_next_trait_solver/src/solve/project_goals.rs index cae73cc2d073c..4bb1fe5be6f01 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + 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>, + ) -> QueryResult { let tcx = self.interner(); let projection_term = goal.predicate.projection_term.to_term(tcx); let goal = goal.with( diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs similarity index 88% rename from compiler/rustc_trait_selection/src/solve/search_graph.rs rename to compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 84878fea10139..b923a121d814c 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -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 { input: CanonicalInput, - 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 SearchGraph { fn allowed_depth_for_nested( tcx: I, stack: &IndexVec>, - ) -> Option { + ) -> Option { 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 SearchGraph { !entry.is_empty() }); } -} -impl<'tcx> SearchGraph> { /// 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>( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput>, - inspect: &mut ProofTreeBuilder>, - mut prove_goal: impl FnMut( - &mut Self, - &mut ProofTreeBuilder>, - ) -> QueryResult>, - ) -> QueryResult> { + tcx: I, + input: CanonicalInput, + inspect: &mut ProofTreeBuilder, + mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, + ) -> QueryResult { 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> { // 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> { /// 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>( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput>, - available_depth: Limit, - inspect: &mut ProofTreeBuilder>, - ) -> Option>> { + tcx: I, + input: CanonicalInput, + available_depth: SolverLimit, + inspect: &mut ProofTreeBuilder, + ) -> Option> { 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 { HasChanged, } -impl<'tcx> SearchGraph> { +impl SearchGraph { /// 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( + fn fixpoint_step_in_task( &mut self, - tcx: TyCtxt<'tcx>, - input: CanonicalInput>, - inspect: &mut ProofTreeBuilder>, + tcx: I, + input: CanonicalInput, + inspect: &mut ProofTreeBuilder, prove_goal: &mut F, - ) -> StepResult> + ) -> StepResult where - F: FnMut(&mut Self, &mut ProofTreeBuilder>) -> QueryResult>, + Infcx: SolverDelegate, + F: FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, { let result = prove_goal(self, inspect); let stack_entry = self.pop_stack(); @@ -533,15 +523,13 @@ impl<'tcx> SearchGraph> { } fn response_no_constraints( - tcx: TyCtxt<'tcx>, - goal: CanonicalInput>, + tcx: I, + goal: CanonicalInput, certainty: Certainty, - ) -> QueryResult> { + ) -> QueryResult { Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty)) } -} -impl SearchGraph { #[allow(rustc::potential_query_instability)] fn check_invariants(&self) { if !cfg!(debug_assertions) { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs similarity index 77% rename from compiler/rustc_trait_selection/src/solve/trait_goals.rs rename to compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index bcb2ea18f78ec..d1419bf5db9a5 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -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; - -impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { - fn self_ty(self) -> Ty<'tcx> { +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}; + +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 assembly::GoalKind for TraitPredicate +where + Infcx: SolverDelegate, + 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 { 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal>, + impl_def_id: I::DefId, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + _guar: I::ErrorGuaranteed, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + source: CandidateSource, + goal: Goal, + assumption: I::Clause, + then: impl FnOnce(&mut EvalCtxt<'_, Infcx>) -> QueryResult, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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, goal_kind: ty::ClosureKind, - ) -> Result>, NoSolution> { + ) -> Result, 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, goal_kind: ty::ClosureKind, - ) -> Result>, NoSolution> { + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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>, NoSolution> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Result, 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 for T {} /// ``` fn consider_structural_builtin_unsize_candidates( - ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, - goal: Goal<'tcx, Self>, - ) -> Vec>> { + ecx: &mut EvalCtxt<'_, Infcx>, + goal: Goal, + ) -> Vec> { 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` -> `Struct` where `T: Unsize` - (&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` - (&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 EvalCtxt<'_, Infcx> +where + Infcx: SolverDelegate, + 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>, - a_region: ty::Region<'tcx>, - b_data: &'tcx ty::List>, - b_region: ty::Region<'tcx>, - ) -> Vec>> { + goal: Goal, + a_data: I::BoundExistentialPredicates, + a_region: I::Region, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + ) -> Vec> { 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>, - b_region: ty::Region<'tcx>, - ) -> Result>, NoSolution> { + goal: Goal, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + ) -> Result, 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>, - a_region: ty::Region<'tcx>, - b_data: &'tcx ty::List>, - b_region: ty::Region<'tcx>, - upcast_principal: Option>, - ) -> Result>, NoSolution> { + goal: Goal, + source: CandidateSource, + a_data: I::BoundExistentialPredicates, + a_region: I::Region, + b_data: I::BoundExistentialPredicates, + b_region: I::Region, + upcast_principal: Option>>, + ) -> Result, 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 = a_data + let a_auto_traits: FxIndexSet = 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>, + target_projection: ty::Binder>| { 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>, NoSolution> { + goal: Goal, + a_elem_ty: I::Ty, + b_elem_ty: I::Ty, + ) -> Result, 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>, NoSolution> { + goal: Goal, + def: I::AdtDef, + a_args: I::GenericArgs, + b_args: I::GenericArgs, + ) -> Result, 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>, - b_tys: &'tcx ty::List>, - ) -> Result>, NoSolution> { + goal: Goal, + a_tys: I::Tys, + b_tys: I::Tys, + ) -> Result, 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>, NoSolution>> { + goal: Goal>, + ) -> Option, 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, + goal: Goal>, constituent_tys: impl Fn( - &EvalCtxt<'_, InferCtxt<'tcx>>, - Ty<'tcx>, - ) -> Result>>, NoSolution>, - ) -> Result>, NoSolution> { + &EvalCtxt<'_, Infcx>, + I::Ty, + ) -> Result>, NoSolution>, + ) -> Result, 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>, + ) -> QueryResult { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) } diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs new file mode 100644 index 0000000000000..a7c8cc5a32b60 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -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; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 3c01d1a65f506..8937ed467a1fd 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -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) } diff --git a/compiler/rustc_trait_selection/src/solve/infcx.rs b/compiler/rustc_trait_selection/src/solve/infcx.rs new file mode 100644 index 0000000000000..e574166cbfc26 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/infcx.rs @@ -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( + interner: TyCtxt<'tcx>, + solver_mode: SolverMode, + canonical: &Canonical<'tcx, V>, + ) -> (Self, V, CanonicalVarValues<'tcx>) + where + V: TypeFoldable>, + { + 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 { + // 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 { + 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 { + // 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 { + 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> + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.0.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + value, + ) + } + + fn enter_forall> + Copy, U>( + &self, + value: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.0.enter_forall(value, f) + } + + fn relate>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result>>, NoSolution> { + self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + } + + fn eq_structurally_relating_aliases>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.0 + .at(&ObligationCause::dummy(), param_env) + .eq_structurally_relating_aliases_no_trace(lhs, rhs) + } + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable>, + { + self.0.resolve_vars_if_possible(value) + } + + fn probe(&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>> { + supertraits(interner, trait_ref) + } + + fn try_const_eval_resolve( + &self, + param_env: ty::ParamEnv<'tcx>, + unevaluated: ty::UnevaluatedConst<'tcx>, + ) -> Option> { + 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>>> { + 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>> { + // 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( + &self, + canonical: Canonical<'tcx, V>, + values: CanonicalVarValues<'tcx>, + ) -> V + where + V: TypeFoldable>, + { + 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>>, + ) -> 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>>, + ) { + 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( + &self, + trait_ref: ty::TraitRef<'tcx>, + lazily_normalize_ty: impl FnMut(Ty<'tcx>) -> Result, E>, + ) -> Result { + 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, 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 { + // 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), + } + } +} diff --git a/compiler/rustc_trait_selection/src/solve/inspect.rs b/compiler/rustc_trait_selection/src/solve/inspect.rs new file mode 100644 index 0000000000000..f100a8c2ff0ef --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/inspect.rs @@ -0,0 +1,4 @@ +pub use rustc_next_trait_solver::solve::inspect::*; + +mod analyse; +pub use analyse::*; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 464c188b6e325..cb621487125f7 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -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>, 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>, 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)) } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/mod.rs b/compiler/rustc_trait_selection/src/solve/inspect/mod.rs deleted file mode 100644 index 60d52305a6be4..0000000000000 --- a/compiler/rustc_trait_selection/src/solve/inspect/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use rustc_middle::traits::solve::inspect::*; - -mod build; -pub(in crate::solve) use build::*; - -mod analyse; -pub use analyse::*; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b401958577121..fe047f9966f37 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -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; diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs deleted file mode 100644 index 4a5f34e354208..0000000000000 --- a/compiler/rustc_type_ir/src/infcx.rs +++ /dev/null @@ -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; - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; - fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; - - 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) -> ::Ty; - fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; - fn opportunistic_resolve_float_var( - &self, - vid: ty::FloatVid, - ) -> ::Ty; - fn opportunistic_resolve_ct_var( - &self, - vid: ty::ConstVid, - ) -> ::Const; - fn opportunistic_resolve_effect_var( - &self, - vid: ty::EffectVid, - ) -> ::Const; - fn opportunistic_resolve_lt_var( - &self, - vid: ty::RegionVid, - ) -> ::Region; - - fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; - - fn next_ty_infer(&self) -> ::Ty; - fn next_const_infer(&self) -> ::Const; - fn fresh_args_for_item( - &self, - def_id: ::DefId, - ) -> ::GenericArgs; - - fn instantiate_binder_with_infer + Copy>( - &self, - value: ty::Binder, - ) -> T; - - fn enter_forall + Copy, U>( - &self, - value: ty::Binder, - f: impl FnOnce(T) -> U, - ) -> U; - - fn relate>( - &self, - param_env: ::ParamEnv, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result::Predicate>>, NoSolution>; - - fn eq_structurally_relating_aliases>( - &self, - param_env: ::ParamEnv, - lhs: T, - rhs: T, - ) -> Result::Predicate>>, NoSolution>; - - fn resolve_vars_if_possible(&self, value: T) -> T - where - T: TypeFoldable; - - fn probe(&self, probe: impl FnOnce() -> T) -> T; -} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 6b84592978a26..64d3400976a8e 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -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>: + Relate + 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>: 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> { match self.kind() { ty::FnPtr(sig) => sig, @@ -126,6 +136,49 @@ pub trait Ty>: _ => 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>: @@ -200,6 +253,12 @@ pub trait Const>: 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>: + From + From { + fn as_type(&self) -> Option { + 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 { + 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 { + 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>: @@ -230,7 +320,7 @@ pub trait Term>: 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>: ty::TermKind::Const(ct) => ct.is_ct_var(), } } + + fn to_alias_term(self) -> Option> { + 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>: @@ -260,8 +363,19 @@ pub trait GenericArgs>: + Default + Relate { + 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>: + UpcastFrom> + UpcastFrom> + UpcastFrom>> + + UpcastFrom> + + UpcastFrom> + + UpcastFrom> + IntoKind>> { fn is_coinductive(self, interner: I) -> bool; @@ -316,9 +433,34 @@ pub trait Clause>: + Eq + TypeFoldable // FIXME: Remove these, uplift the `Upcast` impls. + + UpcastFrom> + UpcastFrom>> + + UpcastFrom> + UpcastFrom>> + + IntoKind>> { + fn as_trait_clause(self) -> Option>> { + self.kind() + .map_bound(|clause| { + if let ty::ClauseKind::Trait(t) = clause { + Some(t) + } else { + None + } + }) + .transpose() + } + fn as_projection_clause(self) -> Option>> { + 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: 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>; + fn is_phantom_data(self) -> bool; // FIXME: perhaps use `all_fields` and expose `FieldDef`. - fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; + fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; fn sized_constraint(self, interner: I) -> Option>; } +pub trait ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable { + fn reveal(self) -> Reveal; + + fn caller_bounds(self) -> impl IntoIterator; +} + pub trait Features: Copy { fn generic_const_exprs(self) -> bool; fn coroutine_clone(self) -> bool; + + fn associated_const_equality(self) -> bool; +} + +pub trait EvaluationCache { + /// Insert a final result into the global cache. + fn insert( + &self, + tcx: I, + key: CanonicalInput, + proof_tree: Option, + additional_depth: usize, + encountered_overflow: bool, + cycle_participants: FxHashSet>, + dep_node: I::DepNodeIndex, + result: QueryResult, + ); + + /// 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, + stack_entries: impl IntoIterator>, + available_depth: usize, + ) -> Option>; +} + +pub trait DefId: Copy + Debug + Hash + Eq + TypeFoldable { + fn as_local(self) -> Option; +} + +pub trait BoundExistentialPredicates: + Copy + + Debug + + Hash + + Eq + + Relate + + IntoIterator>> +{ + fn principal_def_id(self) -> Option; + + fn principal(self) -> Option>>; + + fn auto_traits(self) -> impl IntoIterator; + + fn projection_bounds( + self, + ) -> impl IntoIterator>>; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 11c1f73fef338..59ca95c09cd78 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -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> + IrPrint> { - type DefId: Copy + Debug + Hash + Eq + TypeFoldable; + type DefId: DefId; type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; - type AdtDef: AdtDef; type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref; @@ -45,16 +46,53 @@ pub trait Interner: + Default; type BoundVarKind: Copy + Debug + Hash + Eq; - type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; - type PredefinedOpaques: Copy + Debug + Hash + Eq; - type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable; - type ExternalConstraints: Copy + Debug + Hash + Eq; + type PredefinedOpaques: Copy + + Debug + + Hash + + Eq + + TypeFoldable + + Deref>; + fn mk_predefined_opaques_in_body( + self, + data: PredefinedOpaquesData, + ) -> Self::PredefinedOpaques; + + type DefiningOpaqueTypes: Copy + + Debug + + Hash + + Default + + Eq + + TypeVisitable + + Deref>; type CanonicalGoalEvaluationStepRef: Copy + Debug + Hash + Eq + Deref>; + type CanonicalVars: Copy + + Debug + + Hash + + Eq + + IntoIterator> + + Deref]>> + + Default; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars; + + type ExternalConstraints: Copy + + Debug + + Hash + + Eq + + TypeFoldable + + Deref>; + fn mk_external_constraints( + self, + data: ExternalConstraintsData, + ) -> Self::ExternalConstraints; + + type DepNodeIndex; + fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex); + // Kinds of tys type Ty: Ty; type Tys: Tys; @@ -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 - + IntoIterator>>; + type BoundExistentialPredicates: BoundExistentialPredicates; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + Debug + Relate; type Safety: Safety; @@ -92,14 +125,15 @@ pub trait Interner: type PlaceholderRegion: PlaceholderLike; // Predicates - type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable; + type ParamEnv: ParamEnv; type Predicate: Predicate; type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; - fn expand_abstract_consts>(self, t: T) -> T; + type EvaluationCache: EvaluationCache; + fn evaluation_cache(self, mode: SolverMode) -> Self::EvaluationCache; - fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars; + fn expand_abstract_consts>(self, t: T) -> T; type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; @@ -111,9 +145,11 @@ pub trait Interner: + IntoIterator>; 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; + type AdtDef: AdtDef; + fn adt_def(self, adt_def_id: Self::DefId) -> Self::AdtDef; + fn alias_ty_kind(self, alias: ty::AliasTy) -> ty::AliasTyKind; fn alias_term_kind(self, alias: ty::AliasTerm) -> ty::AliasTermKind; @@ -131,6 +167,8 @@ pub trait Interner: I: Iterator, T: CollectAndApply; + 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>; + fn predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + fn own_predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + // 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; + + // 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>; + + 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; + + fn async_fn_trait_kind_from_def_id(self, trait_def_id: Self::DefId) -> Option; + + fn supertrait_def_ids(self, trait_def_id: Self::DefId) + -> impl IntoIterator; + + 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>; + 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` diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 9a3b324fcd765..cf5ec1ab3febc 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -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 } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index ac9b2808804c6..130ea231bf7ea 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -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::*; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index c0713dc50d269..bf39f92027602 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -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 ty::Binder> { } } +impl UpcastFrom> for TraitPredicate { + fn upcast_from(from: TraitRef, _tcx: I) -> Self { + TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive } + } +} + impl fmt::Debug for TraitPredicate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(effects) printing? diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 99d2fa7449477..7934f996f0bd2 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -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::Predicate> = Canonical>; pub type CanonicalResponse = Canonical>; /// The result of evaluating a canonical query. @@ -143,6 +156,22 @@ pub struct QueryInput { 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 { + pub opaque_types: Vec<(ty::OpaqueTypeKey, 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 { + pub result: QueryResult, + pub proof_tree: Option, + pub additional_depth: usize, + pub encountered_overflow: bool, +}