rustc_trait_selection/solve/
fulfill.rs1use std::marker::PhantomData;
2use std::mem;
3
4use rustc_infer::infer::InferCtxt;
5use rustc_infer::traits::query::NoSolution;
6use rustc_infer::traits::{
7 FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
8};
9use rustc_middle::ty::{TyCtxt, TypeVisitableExt, TypingMode};
10use rustc_next_trait_solver::delegate::SolverDelegate as _;
11use rustc_next_trait_solver::solve::{
12 GoalEvaluation, GoalStalledOn, HasChanged, MaybeInfo, SolverDelegateEvalExt as _,
13 StalledOnCoroutines,
14};
15use thin_vec::ThinVec;
16use tracing::instrument;
17
18use self::derive_errors::*;
19use super::Certainty;
20use super::delegate::SolverDelegate;
21use crate::traits::{FulfillmentError, ScrubbedTraitError};
22
23mod derive_errors;
24
25type PendingObligations<'tcx> =
27 ThinVec<(PredicateObligation<'tcx>, Option<GoalStalledOn<TyCtxt<'tcx>>>)>;
28
29pub struct FulfillmentCtxt<'tcx, E: 'tcx> {
41 obligations: ObligationStorage<'tcx>,
42
43 usable_in_snapshot: usize,
48 _errors: PhantomData<E>,
49}
50
51#[derive(#[automatically_derived]
impl<'tcx> ::core::default::Default for ObligationStorage<'tcx> {
#[inline]
fn default() -> ObligationStorage<'tcx> {
ObligationStorage {
overflowed: ::core::default::Default::default(),
pending: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ObligationStorage<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"ObligationStorage", "overflowed", &self.overflowed, "pending",
&&self.pending)
}
}Debug)]
52struct ObligationStorage<'tcx> {
53 overflowed: Vec<PredicateObligation<'tcx>>,
59 pending: PendingObligations<'tcx>,
60}
61
62impl<'tcx> ObligationStorage<'tcx> {
63 fn register(
64 &mut self,
65 obligation: PredicateObligation<'tcx>,
66 stalled_on: Option<GoalStalledOn<TyCtxt<'tcx>>>,
67 ) {
68 self.pending.push((obligation, stalled_on));
69 }
70
71 fn has_pending_obligations(&self) -> bool {
72 !self.pending.is_empty() || !self.overflowed.is_empty()
73 }
74
75 fn clone_pending(&self) -> PredicateObligations<'tcx> {
76 let mut obligations: PredicateObligations<'tcx> =
77 self.pending.iter().map(|(o, _)| o.clone()).collect();
78 obligations.extend(self.overflowed.iter().cloned());
79 obligations
80 }
81
82 fn drain_pending(
83 &mut self,
84 cond: impl Fn(&PredicateObligation<'tcx>, &Option<GoalStalledOn<TyCtxt<'tcx>>>) -> bool,
85 ) -> PendingObligations<'tcx> {
86 let (unstalled, pending) =
87 mem::take(&mut self.pending).into_iter().partition(|(o, s)| cond(o, s));
88 self.pending = pending;
89 unstalled
90 }
91
92 fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) {
93 infcx.probe(|_| {
94 self.overflowed.extend(
100 self.pending
101 .extract_if(.., |(o, stalled_on)| {
102 let goal = o.as_goal();
103 let result = <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
104 goal,
105 o.cause.span,
106 stalled_on.take(),
107 );
108 #[allow(non_exhaustive_omitted_patterns)] match result {
Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. }) => true,
_ => false,
}matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. }))
109 })
110 .map(|(o, _)| o),
111 );
112 })
113 }
114}
115
116impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> {
117 pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx, E> {
118 if !infcx.next_trait_solver() {
{
::core::panicking::panic_fmt(format_args!("new trait solver fulfillment context created when infcx is set up for old trait solver"));
}
};assert!(
119 infcx.next_trait_solver(),
120 "new trait solver fulfillment context created when \
121 infcx is set up for old trait solver"
122 );
123 FulfillmentCtxt {
124 obligations: Default::default(),
125 usable_in_snapshot: infcx.num_open_snapshots(),
126 _errors: PhantomData,
127 }
128 }
129
130 fn inspect_evaluated_obligation(
131 &self,
132 infcx: &InferCtxt<'tcx>,
133 obligation: &PredicateObligation<'tcx>,
134 result: &Result<GoalEvaluation<TyCtxt<'tcx>>, NoSolution>,
135 ) {
136 if let Some(inspector) = infcx.obligation_inspector.get() {
137 let result = match result {
138 Ok(GoalEvaluation { certainty, .. }) => Ok(*certainty),
139 Err(NoSolution) => Err(NoSolution),
140 };
141 (inspector)(infcx, &obligation, result);
142 }
143 }
144}
145
146impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentCtxt<'tcx, E>
147where
148 E: FromSolverError<'tcx, NextSolverError<'tcx>>,
149{
150 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("register_predicate_obligation",
"rustc_trait_selection::solve::fulfill",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/fulfill.rs"),
::tracing_core::__macro_support::Option::Some(150u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::fulfill"),
::tracing_core::field::FieldSet::new(&["obligation"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = meta.fields().iter();
meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&::tracing::field::debug(&obligation)
as &dyn Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
match (&self.usable_in_snapshot, &infcx.num_open_snapshots()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
};
self.obligations.register(obligation, None);
}
}
}#[instrument(level = "trace", skip(self, infcx))]
151 fn register_predicate_obligation(
152 &mut self,
153 infcx: &InferCtxt<'tcx>,
154 obligation: PredicateObligation<'tcx>,
155 ) {
156 assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
157 self.obligations.register(obligation, None);
158 }
159
160 fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
161 self.obligations
162 .pending
163 .drain(..)
164 .map(|(obligation, _)| NextSolverError::Ambiguity(obligation))
165 .chain(
166 self.obligations
167 .overflowed
168 .drain(..)
169 .map(|obligation| NextSolverError::Overflow(obligation)),
170 )
171 .map(|e| E::from_solver_error(infcx, e))
172 .collect()
173 }
174
175 fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
176 match (&self.usable_in_snapshot, &infcx.num_open_snapshots()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::None);
}
}
};assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
177 let mut errors = Vec::new();
178 loop {
179 let mut any_changed = false;
180 for (mut obligation, stalled_on) in self.obligations.drain_pending(|_, _| true) {
181 if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
182 self.obligations.on_fulfillment_overflow(infcx);
183 return errors;
185 }
186
187 let goal = obligation.as_goal();
188 let delegate = <&SolverDelegate<'tcx>>::from(infcx);
189 if !delegate.disable_trait_solver_fast_paths()
190 && let Some(certainty) =
191 delegate.compute_goal_fast_path(goal, obligation.cause.span)
192 {
193 match certainty {
194 Certainty::Yes => {}
201 Certainty::Maybe(_) => {
202 self.obligations.register(obligation, None);
203 }
204 }
205 continue;
206 }
207
208 let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on);
209 self.inspect_evaluated_obligation(infcx, &obligation, &result);
210 let GoalEvaluation { goal, certainty, has_changed, stalled_on } = match result {
211 Ok(result) => result,
212 Err(NoSolution) => {
213 errors.push(E::from_solver_error(
214 infcx,
215 NextSolverError::TrueError(obligation),
216 ));
217 continue;
218 }
219 };
220
221 obligation.predicate = goal.predicate;
225 if has_changed == HasChanged::Yes {
226 obligation.recursion_depth += 1;
233 any_changed = true;
234 }
235
236 match certainty {
237 Certainty::Yes => {
238 if infcx.in_hir_typeck
250 && (obligation.has_non_region_infer() || obligation.has_free_regions())
251 {
252 infcx.push_hir_typeck_potentially_region_dependent_goal(obligation);
253 }
254 }
255 Certainty::Maybe(_) => self.obligations.register(obligation, stalled_on),
256 }
257 }
258
259 if !any_changed {
260 break;
261 }
262 }
263
264 errors
265 }
266
267 fn has_pending_obligations(&self) -> bool {
268 self.obligations.has_pending_obligations()
269 }
270
271 fn pending_obligations(&self) -> PredicateObligations<'tcx> {
272 self.obligations.clone_pending()
273 }
274
275 fn drain_stalled_obligations_for_coroutines(
276 &mut self,
277 infcx: &InferCtxt<'tcx>,
278 ) -> PredicateObligations<'tcx> {
279 let stalled_coroutines = match infcx.typing_mode_raw().assert_not_erased() {
280 TypingMode::Analysis { defining_opaque_types_and_generators } => {
281 defining_opaque_types_and_generators
282 }
283 TypingMode::Coherence
284 | TypingMode::Borrowck { defining_opaque_types: _ }
285 | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ }
286 | TypingMode::PostAnalysis => return Default::default(),
287 };
288
289 if stalled_coroutines.is_empty() {
290 return Default::default();
291 }
292
293 self.obligations
294 .drain_pending(|_, stalled_on| {
295 stalled_on.as_ref().is_some_and(|s| match s.stalled_certainty {
296 Certainty::Maybe(MaybeInfo {
297 cause: _,
298 opaque_types_jank: _,
299 stalled_on_coroutines: StalledOnCoroutines::Yes,
300 }) => true,
301 Certainty::Maybe(_) | Certainty::Yes => false,
302 })
303 })
304 .into_iter()
305 .map(|(o, _)| o)
306 .collect()
307 }
308}
309
310pub enum NextSolverError<'tcx> {
311 TrueError(PredicateObligation<'tcx>),
312 Ambiguity(PredicateObligation<'tcx>),
313 Overflow(PredicateObligation<'tcx>),
314}
315
316impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tcx> {
317 fn from_solver_error(infcx: &InferCtxt<'tcx>, error: NextSolverError<'tcx>) -> Self {
318 match error {
319 NextSolverError::TrueError(obligation) => {
320 fulfillment_error_for_no_solution(infcx, obligation)
321 }
322 NextSolverError::Ambiguity(obligation) => {
323 fulfillment_error_for_stalled(infcx, obligation)
324 }
325 NextSolverError::Overflow(obligation) => {
326 fulfillment_error_for_overflow(infcx, obligation)
327 }
328 }
329 }
330}
331
332impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for ScrubbedTraitError<'tcx> {
333 fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: NextSolverError<'tcx>) -> Self {
334 match error {
335 NextSolverError::TrueError(_) => ScrubbedTraitError::TrueError,
336 NextSolverError::Ambiguity(_) | NextSolverError::Overflow(_) => {
337 ScrubbedTraitError::Ambiguity
338 }
339 }
340 }
341}