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