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