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