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