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;
67use crate::infer::InferCtxt;
8use crate::infer::canonical::OriginalQueryValues;
9use crate::solve::SolverDelegate;
10use crate::traits::{
11EvaluationResult, ObligationCtxt, OverflowError, PredicateObligation, SelectionContext,
12};
1314pub 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`.
18fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
19self.evaluate_obligation_no_overflow(obligation).may_apply()
20 }
2122/// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
23 /// for more details.
24fn predicate_may_hold_opaque_types_jank(&self, obligation: &PredicateObligation<'tcx>) -> bool {
25if self.next_trait_solver() {
26self.goal_may_hold_opaque_types_jank(Goal::new(
27self.tcx,
28obligation.param_env,
29obligation.predicate,
30 ))
31 } else {
32self.predicate_may_hold(obligation)
33 }
34 }
3536/// See the comment on [OpaqueTypesJank](crate::solve::OpaqueTypesJank)
37 /// for more details.
38fn goal_may_hold_opaque_types_jank(&self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> bool {
39assert!(self.next_trait_solver());
40 <&SolverDelegate<'tcx>>::from(self).root_goal_may_hold_opaque_types_jank(goal)
41 }
4243/// 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 /// ```
70fn predicate_must_hold_considering_regions(
71&self,
72 obligation: &PredicateObligation<'tcx>,
73 ) -> bool {
74self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions()
75 }
7677/// 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.
82fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool {
83self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions()
84 }
8586/// Evaluate a given predicate, capturing overflow and propagating it back.
87fn evaluate_obligation(
88&self,
89 obligation: &PredicateObligation<'tcx>,
90 ) -> Result<EvaluationResult, OverflowError> {
91let mut _orig_values = OriginalQueryValues::default();
9293let param_env = obligation.param_env;
9495if self.next_trait_solver() {
96self.probe(|snapshot| {
97let ocx = ObligationCtxt::new(self);
98ocx.register_obligation(obligation.clone());
99let mut result = EvaluationResult::EvaluatedToOk;
100for error in ocx.evaluate_obligations_error_on_ambiguity() {
101if error.is_true_error() {
102return Ok(EvaluationResult::EvaluatedToErr);
103 } else {
104 result = result.max(EvaluationResult::EvaluatedToAmbig);
105 }
106 }
107if self.opaque_types_added_in_snapshot(snapshot) {
108result = result.max(EvaluationResult::EvaluatedToOkModuloOpaqueTypes);
109 } else if self.region_constraints_added_in_snapshot(snapshot) {
110result = result.max(EvaluationResult::EvaluatedToOkModuloRegions);
111 }
112Ok(result)
113 })
114 } else {
115let c_pred =
116self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values);
117self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred)
118 }
119 }
120121/// 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.
124fn 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`.
131match self.evaluate_obligation(obligation) {
132Ok(result) => result,
133Err(OverflowError::Canonical) => {
134let mut selcx = SelectionContext::new(self);
135selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r {
136 OverflowError::Canonical => {
137span_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 }
147Err(OverflowError::Error(_)) => EvaluationResult::EvaluatedToErr,
148 }
149 }
150}