rustc_next_trait_solver/solve/inspect/
build.rs
1use std::marker::PhantomData;
8
9use derive_where::derive_where;
10use rustc_type_ir::inherent::*;
11use rustc_type_ir::{self as ty, Interner};
12
13use crate::delegate::SolverDelegate;
14use crate::solve::eval_ctxt::canonical;
15use crate::solve::{
16 CanonicalInput, Certainty, GenerateProofTree, Goal, GoalEvaluationKind, GoalSource,
17 QueryResult, inspect,
18};
19
20pub(crate) struct ProofTreeBuilder<D, I = <D as SolverDelegate>::Interner>
41where
42 D: SolverDelegate<Interner = I>,
43 I: Interner,
44{
45 _infcx: PhantomData<D>,
46 state: Option<Box<DebugSolver<I>>>,
47}
48
49#[derive_where(Debug; I: Interner)]
54enum DebugSolver<I: Interner> {
55 Root,
56 GoalEvaluation(WipGoalEvaluation<I>),
57 CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<I>),
58 CanonicalGoalEvaluationStep(WipCanonicalGoalEvaluationStep<I>),
59}
60
61impl<I: Interner> From<WipGoalEvaluation<I>> for DebugSolver<I> {
62 fn from(g: WipGoalEvaluation<I>) -> DebugSolver<I> {
63 DebugSolver::GoalEvaluation(g)
64 }
65}
66
67impl<I: Interner> From<WipCanonicalGoalEvaluation<I>> for DebugSolver<I> {
68 fn from(g: WipCanonicalGoalEvaluation<I>) -> DebugSolver<I> {
69 DebugSolver::CanonicalGoalEvaluation(g)
70 }
71}
72
73impl<I: Interner> From<WipCanonicalGoalEvaluationStep<I>> for DebugSolver<I> {
74 fn from(g: WipCanonicalGoalEvaluationStep<I>) -> DebugSolver<I> {
75 DebugSolver::CanonicalGoalEvaluationStep(g)
76 }
77}
78
79#[derive_where(PartialEq, Eq, Debug; I: Interner)]
80struct WipGoalEvaluation<I: Interner> {
81 pub uncanonicalized_goal: Goal<I, I::Predicate>,
82 pub orig_values: Vec<I::GenericArg>,
83 pub evaluation: Option<WipCanonicalGoalEvaluation<I>>,
84}
85
86impl<I: Interner> WipGoalEvaluation<I> {
87 fn finalize(self) -> inspect::GoalEvaluation<I> {
88 inspect::GoalEvaluation {
89 uncanonicalized_goal: self.uncanonicalized_goal,
90 orig_values: self.orig_values,
91 evaluation: self.evaluation.unwrap().finalize(),
92 }
93 }
94}
95
96#[derive_where(PartialEq, Eq, Debug; I: Interner)]
97struct WipCanonicalGoalEvaluation<I: Interner> {
98 goal: CanonicalInput<I>,
99 encountered_overflow: bool,
100 final_revision: Option<WipCanonicalGoalEvaluationStep<I>>,
103 result: Option<QueryResult<I>>,
104}
105
106impl<I: Interner> WipCanonicalGoalEvaluation<I> {
107 fn finalize(self) -> inspect::CanonicalGoalEvaluation<I> {
108 inspect::CanonicalGoalEvaluation {
109 goal: self.goal,
110 kind: if self.encountered_overflow {
111 assert!(self.final_revision.is_none());
112 inspect::CanonicalGoalEvaluationKind::Overflow
113 } else {
114 let final_revision = self.final_revision.unwrap().finalize();
115 inspect::CanonicalGoalEvaluationKind::Evaluation { final_revision }
116 },
117 result: self.result.unwrap(),
118 }
119 }
120}
121
122#[derive_where(PartialEq, Eq, Debug; I: Interner)]
126struct WipCanonicalGoalEvaluationStep<I: Interner> {
127 var_values: Vec<I::GenericArg>,
134 probe_depth: usize,
135 evaluation: WipProbe<I>,
136}
137
138impl<I: Interner> WipCanonicalGoalEvaluationStep<I> {
139 fn current_evaluation_scope(&mut self) -> &mut WipProbe<I> {
140 let mut current = &mut self.evaluation;
141 for _ in 0..self.probe_depth {
142 match current.steps.last_mut() {
143 Some(WipProbeStep::NestedProbe(p)) => current = p,
144 _ => panic!(),
145 }
146 }
147 current
148 }
149
150 fn finalize(self) -> inspect::Probe<I> {
151 let evaluation = self.evaluation.finalize();
152 match evaluation.kind {
153 inspect::ProbeKind::Root { .. } => evaluation,
154 _ => unreachable!("unexpected root evaluation: {evaluation:?}"),
155 }
156 }
157}
158
159#[derive_where(PartialEq, Eq, Debug; I: Interner)]
160struct WipProbe<I: Interner> {
161 initial_num_var_values: usize,
162 steps: Vec<WipProbeStep<I>>,
163 kind: Option<inspect::ProbeKind<I>>,
164 final_state: Option<inspect::CanonicalState<I, ()>>,
165}
166
167impl<I: Interner> WipProbe<I> {
168 fn finalize(self) -> inspect::Probe<I> {
169 inspect::Probe {
170 steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(),
171 kind: self.kind.unwrap(),
172 final_state: self.final_state.unwrap(),
173 }
174 }
175}
176
177#[derive_where(PartialEq, Eq, Debug; I: Interner)]
178enum WipProbeStep<I: Interner> {
179 AddGoal(GoalSource, inspect::CanonicalState<I, Goal<I, I::Predicate>>),
180 NestedProbe(WipProbe<I>),
181 MakeCanonicalResponse { shallow_certainty: Certainty },
182 RecordImplArgs { impl_args: inspect::CanonicalState<I, I::GenericArgs> },
183}
184
185impl<I: Interner> WipProbeStep<I> {
186 fn finalize(self) -> inspect::ProbeStep<I> {
187 match self {
188 WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
189 WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()),
190 WipProbeStep::RecordImplArgs { impl_args } => {
191 inspect::ProbeStep::RecordImplArgs { impl_args }
192 }
193 WipProbeStep::MakeCanonicalResponse { shallow_certainty } => {
194 inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty }
195 }
196 }
197 }
198}
199
200impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
201 fn new(state: impl Into<DebugSolver<I>>) -> ProofTreeBuilder<D> {
202 ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData }
203 }
204
205 fn opt_nested<T: Into<DebugSolver<I>>>(&self, state: impl FnOnce() -> Option<T>) -> Self {
206 ProofTreeBuilder {
207 state: self.state.as_ref().and_then(|_| Some(state()?.into())).map(Box::new),
208 _infcx: PhantomData,
209 }
210 }
211
212 fn nested<T: Into<DebugSolver<I>>>(&self, state: impl FnOnce() -> T) -> Self {
213 ProofTreeBuilder {
214 state: self.state.as_ref().map(|_| Box::new(state().into())),
215 _infcx: PhantomData,
216 }
217 }
218
219 fn as_mut(&mut self) -> Option<&mut DebugSolver<I>> {
220 self.state.as_deref_mut()
221 }
222
223 pub(crate) fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<D> {
224 let mut nested = ProofTreeBuilder { state: self.state.take(), _infcx: PhantomData };
225 nested.enter_probe();
226 nested
227 }
228
229 pub(crate) fn finalize(self) -> Option<inspect::GoalEvaluation<I>> {
230 match *self.state? {
231 DebugSolver::GoalEvaluation(wip_goal_evaluation) => {
232 Some(wip_goal_evaluation.finalize())
233 }
234 root => unreachable!("unexpected proof tree builder root node: {:?}", root),
235 }
236 }
237
238 pub(crate) fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder<D> {
239 match generate_proof_tree {
240 GenerateProofTree::No => ProofTreeBuilder::new_noop(),
241 GenerateProofTree::Yes => ProofTreeBuilder::new_root(),
242 }
243 }
244
245 fn new_root() -> ProofTreeBuilder<D> {
246 ProofTreeBuilder::new(DebugSolver::Root)
247 }
248
249 fn new_noop() -> ProofTreeBuilder<D> {
250 ProofTreeBuilder { state: None, _infcx: PhantomData }
251 }
252
253 pub(crate) fn is_noop(&self) -> bool {
254 self.state.is_none()
255 }
256
257 pub(in crate::solve) fn new_goal_evaluation(
258 &mut self,
259 goal: Goal<I, I::Predicate>,
260 orig_values: &[I::GenericArg],
261 kind: GoalEvaluationKind,
262 ) -> ProofTreeBuilder<D> {
263 self.opt_nested(|| match kind {
264 GoalEvaluationKind::Root => Some(WipGoalEvaluation {
265 uncanonicalized_goal: goal,
266 orig_values: orig_values.to_vec(),
267 evaluation: None,
268 }),
269 GoalEvaluationKind::Nested => None,
270 })
271 }
272
273 pub(crate) fn new_canonical_goal_evaluation(
274 &mut self,
275 goal: CanonicalInput<I>,
276 ) -> ProofTreeBuilder<D> {
277 self.nested(|| WipCanonicalGoalEvaluation {
278 goal,
279 encountered_overflow: false,
280 final_revision: None,
281 result: None,
282 })
283 }
284
285 pub(crate) fn canonical_goal_evaluation(
286 &mut self,
287 canonical_goal_evaluation: ProofTreeBuilder<D>,
288 ) {
289 if let Some(this) = self.as_mut() {
290 match (this, *canonical_goal_evaluation.state.unwrap()) {
291 (
292 DebugSolver::GoalEvaluation(goal_evaluation),
293 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation),
294 ) => {
295 let prev = goal_evaluation.evaluation.replace(canonical_goal_evaluation);
296 assert_eq!(prev, None);
297 }
298 _ => unreachable!(),
299 }
300 }
301 }
302
303 pub(crate) fn canonical_goal_evaluation_overflow(&mut self) {
304 if let Some(this) = self.as_mut() {
305 match this {
306 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
307 canonical_goal_evaluation.encountered_overflow = true;
308 }
309 _ => unreachable!(),
310 };
311 }
312 }
313
314 pub(crate) fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<D>) {
315 if let Some(this) = self.as_mut() {
316 match this {
317 DebugSolver::Root => *this = *goal_evaluation.state.unwrap(),
318 DebugSolver::CanonicalGoalEvaluationStep(_) => {
319 assert!(goal_evaluation.state.is_none())
320 }
321 _ => unreachable!(),
322 }
323 }
324 }
325
326 pub(crate) fn new_goal_evaluation_step(
327 &mut self,
328 var_values: ty::CanonicalVarValues<I>,
329 ) -> ProofTreeBuilder<D> {
330 self.nested(|| WipCanonicalGoalEvaluationStep {
331 var_values: var_values.var_values.to_vec(),
332 evaluation: WipProbe {
333 initial_num_var_values: var_values.len(),
334 steps: vec![],
335 kind: None,
336 final_state: None,
337 },
338 probe_depth: 0,
339 })
340 }
341
342 pub(crate) fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<D>) {
343 if let Some(this) = self.as_mut() {
344 match (this, *goal_evaluation_step.state.unwrap()) {
345 (
346 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluations),
347 DebugSolver::CanonicalGoalEvaluationStep(goal_evaluation_step),
348 ) => {
349 canonical_goal_evaluations.final_revision = Some(goal_evaluation_step);
350 }
351 _ => unreachable!(),
352 }
353 }
354 }
355
356 pub(crate) fn add_var_value<T: Into<I::GenericArg>>(&mut self, arg: T) {
357 match self.as_mut() {
358 None => {}
359 Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
360 state.var_values.push(arg.into());
361 }
362 Some(s) => panic!("tried to add var values to {s:?}"),
363 }
364 }
365
366 fn enter_probe(&mut self) {
367 match self.as_mut() {
368 None => {}
369 Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
370 let initial_num_var_values = state.var_values.len();
371 state.current_evaluation_scope().steps.push(WipProbeStep::NestedProbe(WipProbe {
372 initial_num_var_values,
373 steps: vec![],
374 kind: None,
375 final_state: None,
376 }));
377 state.probe_depth += 1;
378 }
379 Some(s) => panic!("tried to start probe to {s:?}"),
380 }
381 }
382
383 pub(crate) fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<I>) {
384 match self.as_mut() {
385 None => {}
386 Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
387 let prev = state.current_evaluation_scope().kind.replace(probe_kind);
388 assert_eq!(prev, None);
389 }
390 _ => panic!(),
391 }
392 }
393
394 pub(crate) fn probe_final_state(
395 &mut self,
396 delegate: &D,
397 max_input_universe: ty::UniverseIndex,
398 ) {
399 match self.as_mut() {
400 None => {}
401 Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
402 let final_state = canonical::make_canonical_state(
403 delegate,
404 &state.var_values,
405 max_input_universe,
406 (),
407 );
408 let prev = state.current_evaluation_scope().final_state.replace(final_state);
409 assert_eq!(prev, None);
410 }
411 _ => panic!(),
412 }
413 }
414
415 pub(crate) fn add_normalizes_to_goal(
416 &mut self,
417 delegate: &D,
418 max_input_universe: ty::UniverseIndex,
419 goal: Goal<I, ty::NormalizesTo<I>>,
420 ) {
421 self.add_goal(
422 delegate,
423 max_input_universe,
424 GoalSource::Misc,
425 goal.with(delegate.cx(), goal.predicate),
426 );
427 }
428
429 pub(crate) fn add_goal(
430 &mut self,
431 delegate: &D,
432 max_input_universe: ty::UniverseIndex,
433 source: GoalSource,
434 goal: Goal<I, I::Predicate>,
435 ) {
436 match self.as_mut() {
437 None => {}
438 Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
439 let goal = canonical::make_canonical_state(
440 delegate,
441 &state.var_values,
442 max_input_universe,
443 goal,
444 );
445 state.current_evaluation_scope().steps.push(WipProbeStep::AddGoal(source, goal))
446 }
447 _ => panic!(),
448 }
449 }
450
451 pub(crate) fn record_impl_args(
452 &mut self,
453 delegate: &D,
454 max_input_universe: ty::UniverseIndex,
455 impl_args: I::GenericArgs,
456 ) {
457 match self.as_mut() {
458 Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
459 let impl_args = canonical::make_canonical_state(
460 delegate,
461 &state.var_values,
462 max_input_universe,
463 impl_args,
464 );
465 state
466 .current_evaluation_scope()
467 .steps
468 .push(WipProbeStep::RecordImplArgs { impl_args });
469 }
470 None => {}
471 _ => panic!(),
472 }
473 }
474
475 pub(crate) fn make_canonical_response(&mut self, shallow_certainty: Certainty) {
476 match self.as_mut() {
477 Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
478 state
479 .current_evaluation_scope()
480 .steps
481 .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty });
482 }
483 None => {}
484 _ => panic!(),
485 }
486 }
487
488 pub(crate) fn finish_probe(mut self) -> ProofTreeBuilder<D> {
489 match self.as_mut() {
490 None => {}
491 Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => {
492 assert_ne!(state.probe_depth, 0);
493 let num_var_values = state.current_evaluation_scope().initial_num_var_values;
494 state.var_values.truncate(num_var_values);
495 state.probe_depth -= 1;
496 }
497 _ => panic!(),
498 }
499
500 self
501 }
502
503 pub(crate) fn query_result(&mut self, result: QueryResult<I>) {
504 if let Some(this) = self.as_mut() {
505 match this {
506 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
507 assert_eq!(canonical_goal_evaluation.result.replace(result), None);
508 }
509 DebugSolver::CanonicalGoalEvaluationStep(evaluation_step) => {
510 assert_eq!(
511 evaluation_step
512 .evaluation
513 .kind
514 .replace(inspect::ProbeKind::Root { result }),
515 None
516 );
517 }
518 _ => unreachable!(),
519 }
520 }
521 }
522}