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