]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
Separate trait selection from ambiguity reporting.
[rust.git] / compiler / rustc_trait_selection / src / traits / query / evaluate_obligation.rs
1 use rustc_middle::ty;
2
3 use crate::infer::canonical::OriginalQueryValues;
4 use crate::infer::InferCtxt;
5 use crate::traits::{EvaluationResult, OverflowError, PredicateObligation, SelectionContext};
6
7 pub trait InferCtxtExt<'tcx> {
8     fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool;
9
10     fn predicate_must_hold_considering_regions(
11         &self,
12         obligation: &PredicateObligation<'tcx>,
13     ) -> bool;
14
15     fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool;
16
17     fn evaluate_obligation(
18         &self,
19         obligation: &PredicateObligation<'tcx>,
20     ) -> Result<EvaluationResult, OverflowError>;
21
22     // Helper function that canonicalizes and runs the query. If an
23     // overflow results, we re-run it in the local context so we can
24     // report a nice error.
25     /*crate*/
26     fn evaluate_obligation_no_overflow(
27         &self,
28         obligation: &PredicateObligation<'tcx>,
29     ) -> EvaluationResult;
30 }
31
32 impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
33     /// Evaluates whether the predicate can be satisfied (by any means)
34     /// in the given `ParamEnv`.
35     fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
36         self.evaluate_obligation_no_overflow(obligation).may_apply()
37     }
38
39     /// Evaluates whether the predicate can be satisfied in the given
40     /// `ParamEnv`, and returns `false` if not certain. However, this is
41     /// not entirely accurate if inference variables are involved.
42     ///
43     /// This version may conservatively fail when outlives obligations
44     /// are required.
45     fn predicate_must_hold_considering_regions(
46         &self,
47         obligation: &PredicateObligation<'tcx>,
48     ) -> bool {
49         self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions()
50     }
51
52     /// Evaluates whether the predicate can be satisfied in the given
53     /// `ParamEnv`, and returns `false` if not certain. However, this is
54     /// not entirely accurate if inference variables are involved.
55     ///
56     /// This version ignores all outlives constraints.
57     fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool {
58         self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions()
59     }
60
61     /// Evaluate a given predicate, capturing overflow and propagating it back.
62     fn evaluate_obligation(
63         &self,
64         obligation: &PredicateObligation<'tcx>,
65     ) -> Result<EvaluationResult, OverflowError> {
66         let mut _orig_values = OriginalQueryValues::default();
67
68         let param_env = match obligation.predicate.kind().skip_binder() {
69             ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
70                 // we ignore the value set to it.
71                 let mut _constness = pred.constness;
72                 obligation
73                     .param_env
74                     .with_constness(_constness.and(obligation.param_env.constness()))
75             }
76             // constness has no effect on the given predicate.
77             _ => obligation.param_env.without_const(),
78         };
79
80         let c_pred = self
81             .canonicalize_query_keep_static(param_env.and(obligation.predicate), &mut _orig_values);
82         // Run canonical query. If overflow occurs, rerun from scratch but this time
83         // in standard trait query mode so that overflow is handled appropriately
84         // within `SelectionContext`.
85         self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
86     }
87
88     // Helper function that canonicalizes and runs the query. If an
89     // overflow results, we re-run it in the local context so we can
90     // report a nice error.
91     fn evaluate_obligation_no_overflow(
92         &self,
93         obligation: &PredicateObligation<'tcx>,
94     ) -> EvaluationResult {
95         match self.evaluate_obligation(obligation) {
96             Ok(result) => result,
97             Err(OverflowError::Canonical) => {
98                 let mut selcx = SelectionContext::new(&self);
99                 selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
100                     OverflowError::Canonical => {
101                         span_bug!(
102                             obligation.cause.span,
103                             "Overflow should be caught earlier in standard query mode: {:?}, {:?}",
104                             obligation,
105                             r,
106                         )
107                     }
108                     OverflowError::ErrorReporting => EvaluationResult::EvaluatedToErr,
109                     OverflowError::Error(_) => EvaluationResult::EvaluatedToErr,
110                 })
111             }
112             Err(OverflowError::ErrorReporting) => EvaluationResult::EvaluatedToErr,
113             Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr,
114         }
115     }
116 }