]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_trait_selection/src/traits/engine.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / engine.rs
CommitLineData
064997fb 1use std::cell::RefCell;
487cf647 2use std::fmt::Debug;
ba9703b0 3
ba9703b0 4use super::TraitEngine;
f9f354fc 5use super::{ChalkFulfillmentContext, FulfillmentContext};
9c376795 6use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt;
487cf647
FG
7use crate::traits::NormalizeExt;
8use rustc_data_structures::fx::FxIndexSet;
353b0b11 9use rustc_errors::ErrorGuaranteed;
f2b60f7d 10use rustc_hir::def_id::{DefId, LocalDefId};
487cf647
FG
11use rustc_infer::infer::at::ToTrace;
12use rustc_infer::infer::canonical::{
9c376795 13 Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse,
487cf647 14};
353b0b11
FG
15use rustc_infer::infer::outlives::env::OutlivesEnvironment;
16use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
487cf647 17use rustc_infer::traits::query::Fallible;
064997fb
FG
18use rustc_infer::traits::{
19 FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
20};
487cf647 21use rustc_middle::arena::ArenaAllocatable;
064997fb
FG
22use rustc_middle::ty::error::TypeError;
23use rustc_middle::ty::ToPredicate;
24use rustc_middle::ty::TypeFoldable;
25use rustc_middle::ty::{self, Ty, TyCtxt};
9c376795 26use rustc_session::config::TraitSolver;
f2b60f7d 27use rustc_span::Span;
ba9703b0
XL
28
29pub trait TraitEngineExt<'tcx> {
30 fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
f2b60f7d 31 fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self>;
ba9703b0
XL
32}
33
34impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
f9f354fc 35 fn new(tcx: TyCtxt<'tcx>) -> Box<Self> {
9c376795
FG
36 match tcx.sess.opts.unstable_opts.trait_solver {
37 TraitSolver::Classic => Box::new(FulfillmentContext::new()),
38 TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new()),
39 TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()),
f9f354fc 40 }
ba9703b0 41 }
f2b60f7d
FG
42
43 fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
9c376795
FG
44 match tcx.sess.opts.unstable_opts.trait_solver {
45 TraitSolver::Classic => Box::new(FulfillmentContext::new_in_snapshot()),
46 TraitSolver::Chalk => Box::new(ChalkFulfillmentContext::new_in_snapshot()),
47 TraitSolver::Next => Box::new(NextFulfillmentCtxt::new()),
f2b60f7d
FG
48 }
49 }
ba9703b0 50}
064997fb
FG
51
52/// Used if you want to have pleasant experience when dealing
53/// with obligations outside of hir or mir typeck.
54pub struct ObligationCtxt<'a, 'tcx> {
2b03887a 55 pub infcx: &'a InferCtxt<'tcx>,
064997fb
FG
56 engine: RefCell<Box<dyn TraitEngine<'tcx>>>,
57}
58
59impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
2b03887a 60 pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
064997fb
FG
61 Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx.tcx)) }
62 }
63
2b03887a 64 pub fn new_in_snapshot(infcx: &'a InferCtxt<'tcx>) -> Self {
f2b60f7d
FG
65 Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new_in_snapshot(infcx.tcx)) }
66 }
67
064997fb
FG
68 pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) {
69 self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation);
70 }
71
72 pub fn register_obligations(
73 &self,
74 obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
75 ) {
76 // Can't use `register_predicate_obligations` because the iterator
77 // may also use this `ObligationCtxt`.
78 for obligation in obligations {
79 self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation)
80 }
81 }
82
83 pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
84 let InferOk { value, obligations } = infer_ok;
85 self.engine.borrow_mut().register_predicate_obligations(self.infcx, obligations);
86 value
87 }
88
89 /// Requires that `ty` must implement the trait with `def_id` in
90 /// the given environment. This trait must not have any type
91 /// parameters (except for `Self`).
92 pub fn register_bound(
93 &self,
94 cause: ObligationCause<'tcx>,
95 param_env: ty::ParamEnv<'tcx>,
96 ty: Ty<'tcx>,
97 def_id: DefId,
98 ) {
99 let tcx = self.infcx.tcx;
487cf647 100 let trait_ref = tcx.mk_trait_ref(def_id, [ty]);
064997fb
FG
101 self.register_obligation(Obligation {
102 cause,
103 recursion_depth: 0,
104 param_env,
105 predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
106 });
107 }
108
9ffffee4 109 pub fn normalize<T: TypeFoldable<TyCtxt<'tcx>>>(
064997fb 110 &self,
487cf647 111 cause: &ObligationCause<'tcx>,
064997fb
FG
112 param_env: ty::ParamEnv<'tcx>,
113 value: T,
114 ) -> T {
487cf647 115 let infer_ok = self.infcx.at(&cause, param_env).normalize(value);
064997fb
FG
116 self.register_infer_ok_obligations(infer_ok)
117 }
118
487cf647
FG
119 /// Makes `expected <: actual`.
120 pub fn eq_exp<T>(
121 &self,
122 cause: &ObligationCause<'tcx>,
123 param_env: ty::ParamEnv<'tcx>,
124 a_is_expected: bool,
125 a: T,
126 b: T,
127 ) -> Result<(), TypeError<'tcx>>
128 where
129 T: ToTrace<'tcx>,
130 {
131 self.infcx
132 .at(cause, param_env)
353b0b11 133 .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, a, b)
487cf647
FG
134 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
135 }
136
137 pub fn eq<T: ToTrace<'tcx>>(
064997fb
FG
138 &self,
139 cause: &ObligationCause<'tcx>,
140 param_env: ty::ParamEnv<'tcx>,
487cf647
FG
141 expected: T,
142 actual: T,
064997fb 143 ) -> Result<(), TypeError<'tcx>> {
487cf647
FG
144 self.infcx
145 .at(cause, param_env)
353b0b11 146 .eq(DefineOpaqueTypes::Yes, expected, actual)
487cf647
FG
147 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
148 }
149
150 /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`.
151 pub fn sub<T: ToTrace<'tcx>>(
152 &self,
153 cause: &ObligationCause<'tcx>,
154 param_env: ty::ParamEnv<'tcx>,
155 expected: T,
156 actual: T,
157 ) -> Result<(), TypeError<'tcx>> {
158 self.infcx
159 .at(cause, param_env)
353b0b11 160 .sub(DefineOpaqueTypes::Yes, expected, actual)
487cf647
FG
161 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
162 }
163
164 /// Checks whether `expected` is a supertype of `actual`: `expected :> actual`.
165 pub fn sup<T: ToTrace<'tcx>>(
166 &self,
167 cause: &ObligationCause<'tcx>,
168 param_env: ty::ParamEnv<'tcx>,
169 expected: T,
170 actual: T,
171 ) -> Result<(), TypeError<'tcx>> {
172 self.infcx
173 .at(cause, param_env)
353b0b11 174 .sup(DefineOpaqueTypes::Yes, expected, actual)
487cf647
FG
175 .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
176 }
177
353b0b11 178 #[must_use]
487cf647
FG
179 pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> {
180 self.engine.borrow_mut().select_where_possible(self.infcx)
064997fb
FG
181 }
182
353b0b11 183 #[must_use]
064997fb
FG
184 pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
185 self.engine.borrow_mut().select_all_or_error(self.infcx)
186 }
f2b60f7d 187
353b0b11
FG
188 /// Resolves regions and reports errors.
189 ///
190 /// Takes ownership of the context as doing trait solving afterwards
191 /// will result in region constraints getting ignored.
192 pub fn resolve_regions_and_report_errors(
193 self,
194 generic_param_scope: LocalDefId,
195 outlives_env: &OutlivesEnvironment<'tcx>,
196 ) -> Result<(), ErrorGuaranteed> {
197 let errors = self.infcx.resolve_regions(&outlives_env);
198 if errors.is_empty() {
199 Ok(())
200 } else {
201 Err(self.infcx.err_ctxt().report_region_errors(generic_param_scope, &errors))
202 }
203 }
204
f2b60f7d
FG
205 pub fn assumed_wf_types(
206 &self,
207 param_env: ty::ParamEnv<'tcx>,
208 span: Span,
209 def_id: LocalDefId,
487cf647 210 ) -> FxIndexSet<Ty<'tcx>> {
f2b60f7d
FG
211 let tcx = self.infcx.tcx;
212 let assumed_wf_types = tcx.assumed_wf_types(def_id);
487cf647 213 let mut implied_bounds = FxIndexSet::default();
9ffffee4 214 let cause = ObligationCause::misc(span, def_id);
f2b60f7d
FG
215 for ty in assumed_wf_types {
216 // FIXME(@lcnr): rustc currently does not check wf for types
217 // pre-normalization, meaning that implied bounds are sometimes
218 // incorrect. See #100910 for more details.
219 //
220 // Not adding the unnormalized types here mostly fixes that, except
221 // that there are projections which are still ambiguous in the item definition
222 // but do normalize successfully when using the item, see #98543.
223 //
224 // Anyways, I will hopefully soon change implied bounds to make all of this
225 // sound and then uncomment this line again.
226
227 // implied_bounds.insert(ty);
487cf647 228 let normalized = self.normalize(&cause, param_env, ty);
f2b60f7d
FG
229 implied_bounds.insert(normalized);
230 }
231 implied_bounds
232 }
487cf647
FG
233
234 pub fn make_canonicalized_query_response<T>(
235 &self,
236 inference_vars: CanonicalVarValues<'tcx>,
237 answer: T,
9c376795 238 ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
487cf647 239 where
9ffffee4 240 T: Debug + TypeFoldable<TyCtxt<'tcx>>,
487cf647
FG
241 Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
242 {
243 self.infcx.make_canonicalized_query_response(
244 inference_vars,
245 answer,
246 &mut **self.engine.borrow_mut(),
247 )
248 }
064997fb 249}