rustc_trait_selection/traits/query/
evaluate_obligation.rs

1use rustc_infer::traits::solve::Goal;
2use rustc_macros::extension;
3use rustc_middle::span_bug;
4use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
5
6use crate::infer::InferCtxt;
7use crate::infer::canonical::OriginalQueryValues;
8use crate::solve::SolverDelegate;
9use crate::traits::{
10    EvaluationResult, ObligationCtxt, OverflowError, PredicateObligation, SelectionContext,
11};
12
13#[extension(pub trait InferCtxtExt<'tcx>)]
14impl<'tcx> InferCtxt<'tcx> {
15    /// Evaluates whether the predicate can be satisfied (by any means)
16    /// in the given `ParamEnv`.
17    fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
18        self.evaluate_obligation_no_overflow(obligation).may_apply()
19    }
20
21    /// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
22    /// for more details.
23    fn predicate_may_hold_opaque_types_jank(&self, obligation: &PredicateObligation<'tcx>) -> bool {
24        if self.next_trait_solver() {
25            <&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(Goal::new(
26                self.tcx,
27                obligation.param_env,
28                obligation.predicate,
29            ))
30        } else {
31            self.predicate_may_hold(obligation)
32        }
33    }
34
35    /// Evaluates whether the predicate can be satisfied in the given
36    /// `ParamEnv`, and returns `false` if not certain. However, this is
37    /// not entirely accurate if inference variables are involved.
38    ///
39    /// This version may conservatively fail when outlives obligations
40    /// are required. Therefore, this version should only be used for
41    /// optimizations or diagnostics and be treated as if it can always
42    /// return `false`.
43    ///
44    /// # Example
45    ///
46    /// ```
47    /// # #![allow(dead_code)]
48    /// trait Trait {}
49    ///
50    /// fn check<T: Trait>() {}
51    ///
52    /// fn foo<T: 'static>()
53    /// where
54    ///     &'static T: Trait,
55    /// {
56    ///     // Evaluating `&'?0 T: Trait` adds a `'?0: 'static` outlives obligation,
57    ///     // which means that `predicate_must_hold_considering_regions` will return
58    ///     // `false`.
59    ///     check::<&'_ T>();
60    /// }
61    /// ```
62    fn predicate_must_hold_considering_regions(
63        &self,
64        obligation: &PredicateObligation<'tcx>,
65    ) -> bool {
66        self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions()
67    }
68
69    /// Evaluates whether the predicate can be satisfied in the given
70    /// `ParamEnv`, and returns `false` if not certain. However, this is
71    /// not entirely accurate if inference variables are involved.
72    ///
73    /// This version ignores all outlives constraints.
74    fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool {
75        self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions()
76    }
77
78    /// Evaluate a given predicate, capturing overflow and propagating it back.
79    fn evaluate_obligation(
80        &self,
81        obligation: &PredicateObligation<'tcx>,
82    ) -> Result<EvaluationResult, OverflowError> {
83        let mut _orig_values = OriginalQueryValues::default();
84
85        let param_env = obligation.param_env;
86
87        if self.next_trait_solver() {
88            self.probe(|snapshot| {
89                let ocx = ObligationCtxt::new(self);
90                ocx.register_obligation(obligation.clone());
91                let mut result = EvaluationResult::EvaluatedToOk;
92                for error in ocx.select_all_or_error() {
93                    if error.is_true_error() {
94                        return Ok(EvaluationResult::EvaluatedToErr);
95                    } else {
96                        result = result.max(EvaluationResult::EvaluatedToAmbig);
97                    }
98                }
99                if self.opaque_types_added_in_snapshot(snapshot) {
100                    result = result.max(EvaluationResult::EvaluatedToOkModuloOpaqueTypes);
101                } else if self.region_constraints_added_in_snapshot(snapshot) {
102                    result = result.max(EvaluationResult::EvaluatedToOkModuloRegions);
103                }
104                Ok(result)
105            })
106        } else {
107            let c_pred =
108                self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values);
109            self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred)
110        }
111    }
112
113    /// Helper function that canonicalizes and runs the query. If an
114    /// overflow results, we re-run it in the local context so we can
115    /// report a nice error.
116    fn evaluate_obligation_no_overflow(
117        &self,
118        obligation: &PredicateObligation<'tcx>,
119    ) -> EvaluationResult {
120        // Run canonical query. If overflow occurs, rerun from scratch but this time
121        // in standard trait query mode so that overflow is handled appropriately
122        // within `SelectionContext`.
123        match self.evaluate_obligation(obligation) {
124            Ok(result) => result,
125            Err(OverflowError::Canonical) => {
126                let mut selcx = SelectionContext::new(self);
127                selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
128                    OverflowError::Canonical => {
129                        span_bug!(
130                            obligation.cause.span,
131                            "Overflow should be caught earlier in standard query mode: {:?}, {:?}",
132                            obligation,
133                            r,
134                        )
135                    }
136                    OverflowError::Error(_) => EvaluationResult::EvaluatedToErr,
137                })
138            }
139            Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr,
140        }
141    }
142}