Skip to main content

rustc_trait_selection/traits/query/
evaluate_obligation.rs

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