1use std::assert_matches;
13
14use rustc_infer::infer::InferCtxt;
15use rustc_macros::extension;
16use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult};
17use rustc_middle::ty;
18use rustc_middle::ty::{RequiredDepth, TyCtxt, VisitorResult, try_visit};
19use rustc_next_trait_solver::canonical::instantiate_canonical_state;
20use rustc_next_trait_solver::solve::{MaybeCause, MaybeInfo, SolverDelegateEvalExt as _, inspect};
21use rustc_span::{Span, bug};
22use thin_vec::ThinVec;
23use tracing::instrument;
24
25use crate::solve::delegate::SolverDelegate;
26
27pub struct InspectConfig {
28 pub max_depth: usize,
29}
30
31pub struct InspectGoal<'a, 'tcx> {
32 infcx: &'a SolverDelegate<'tcx>,
33 depth: usize,
35 required_depth: RequiredDepth,
37 orig_values: ThinVec<ty::GenericArg<'tcx>>,
38 prev_universe: ty::UniverseIndex,
39 goal: Goal<'tcx, ty::Predicate<'tcx>>,
40 result: Result<Certainty, NoSolution>,
41 final_revision: &'tcx inspect::Probe<TyCtxt<'tcx>>,
42 source: GoalSource,
43}
44
45pub struct InspectCandidate<'a, 'tcx> {
46 goal: &'a InspectGoal<'a, 'tcx>,
47 kind: inspect::ProbeKind<TyCtxt<'tcx>>,
48 steps: Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
49 final_state: inspect::CanonicalState<TyCtxt<'tcx>, ()>,
50 result: QueryResult<'tcx>,
51 shallow_certainty: Certainty,
52}
53
54impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
55 pub fn kind(&self) -> inspect::ProbeKind<TyCtxt<'tcx>> {
56 self.kind
57 }
58
59 pub fn result(&self) -> Result<Certainty, NoSolution> {
60 self.result.map(|c| c.value.certainty)
61 }
62
63 pub fn goal(&self) -> &'a InspectGoal<'a, 'tcx> {
64 self.goal
65 }
66
67 pub fn shallow_certainty(&self) -> Certainty {
76 self.shallow_certainty
77 }
78
79 pub fn visit_nested_no_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
83 for goal in self.instantiate_nested_goals(visitor.span()) {
84 match ::rustc_ast_ir::visit::VisitorResult::branch(goal.visit_with(visitor)) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(goal.visit_with(visitor));
85 }
86
87 V::Result::output()
88 }
89
90 {}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::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("instantiate_nested_goals",
"rustc_trait_selection::solve::inspect::analyse",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/0abfedbc7cd4e725f126913880c95800394f7c37/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs"),
::tracing_core::__macro_support::Option::Some(94u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::inspect::analyse"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("goal")
}> =
::tracing::__macro_support::FieldName::new("goal");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("steps")
}> =
::tracing::__macro_support::FieldName::new("steps");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::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};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.goal.goal)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.steps)
as &dyn ::tracing::field::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: Vec<InspectGoal<'a, 'tcx>> =
loop {};
return __tracing_attr_fake_return;
}
{
let infcx = self.goal.infcx;
let mut orig_values = self.goal.orig_values.clone();
let mut instantiated_goals = ::alloc::vec::Vec::new();
for step in &self.steps {
match **step {
inspect::ProbeStep::AddGoal(source, goal) =>
instantiated_goals.push((source,
instantiate_canonical_state(infcx, span,
self.goal.prev_universe, &mut orig_values, goal))),
inspect::ProbeStep::RecordImplArgs { .. } => {}
inspect::ProbeStep::MakeCanonicalResponse { .. } |
inspect::ProbeStep::NestedProbe(_) =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
let () =
instantiate_canonical_state(infcx, span,
self.goal.prev_universe, &mut orig_values,
self.final_state);
instantiated_goals.into_iter().map(|(source, goal)|
self.instantiate_proof_tree_for_nested_goal(source, goal,
span)).collect()
}
}
}#[instrument(
95 level = "debug",
96 skip_all,
97 fields(goal = ?self.goal.goal, steps = ?self.steps)
98 )]
99 pub fn instantiate_nested_goals(&self, span: Span) -> Vec<InspectGoal<'a, 'tcx>> {
100 let infcx = self.goal.infcx;
101 let mut orig_values = self.goal.orig_values.clone();
102
103 let mut instantiated_goals = vec![];
104 for step in &self.steps {
105 match **step {
106 inspect::ProbeStep::AddGoal(source, goal) => instantiated_goals.push((
107 source,
108 instantiate_canonical_state(
109 infcx,
110 span,
111 self.goal.prev_universe,
112 &mut orig_values,
113 goal,
114 ),
115 )),
116 inspect::ProbeStep::RecordImplArgs { .. } => {}
117 inspect::ProbeStep::MakeCanonicalResponse { .. }
118 | inspect::ProbeStep::NestedProbe(_) => unreachable!(),
119 }
120 }
121
122 let () = instantiate_canonical_state(
123 infcx,
124 span,
125 self.goal.prev_universe,
126 &mut orig_values,
127 self.final_state,
128 );
129
130 instantiated_goals
131 .into_iter()
132 .map(|(source, goal)| self.instantiate_proof_tree_for_nested_goal(source, goal, span))
133 .collect()
134 }
135
136 {}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::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("instantiate_impl_args",
"rustc_trait_selection::solve::inspect::analyse",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/0abfedbc7cd4e725f126913880c95800394f7c37/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs"),
::tracing_core::__macro_support::Option::Some(139u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::inspect::analyse"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("goal")
}> =
::tracing::__macro_support::FieldName::new("goal");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("steps")
}> =
::tracing::__macro_support::FieldName::new("steps");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::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};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.goal.goal)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self.steps)
as &dyn ::tracing::field::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: ty::GenericArgsRef<'tcx> =
loop {};
return __tracing_attr_fake_return;
}
{
let infcx = self.goal.infcx;
let mut orig_values = self.goal.orig_values.clone();
for step in &self.steps {
match **step {
inspect::ProbeStep::RecordImplArgs { impl_args } => {
let impl_args =
instantiate_canonical_state(infcx, span,
self.goal.prev_universe, &mut orig_values, impl_args);
let () =
instantiate_canonical_state(infcx, span,
self.goal.prev_universe, &mut orig_values,
self.final_state);
return infcx.deeply_resolve_via_unification_table(impl_args);
}
inspect::ProbeStep::AddGoal(..) => {}
inspect::ProbeStep::MakeCanonicalResponse { .. } |
inspect::ProbeStep::NestedProbe(_) =>
::core::panicking::panic("internal error: entered unreachable code"),
}
}
::rustc_span::macros::bug_impl(None,
format_args!("expected impl args probe step for `instantiate_impl_args`"),
Location::caller());
}
}
}#[instrument(
140 level = "debug",
141 skip_all,
142 fields(goal = ?self.goal.goal, steps = ?self.steps)
143 )]
144 pub fn instantiate_impl_args(&self, span: Span) -> ty::GenericArgsRef<'tcx> {
145 let infcx = self.goal.infcx;
146 let mut orig_values = self.goal.orig_values.clone();
147
148 for step in &self.steps {
149 match **step {
150 inspect::ProbeStep::RecordImplArgs { impl_args } => {
151 let impl_args = instantiate_canonical_state(
152 infcx,
153 span,
154 self.goal.prev_universe,
155 &mut orig_values,
156 impl_args,
157 );
158
159 let () = instantiate_canonical_state(
160 infcx,
161 span,
162 self.goal.prev_universe,
163 &mut orig_values,
164 self.final_state,
165 );
166
167 return infcx.deeply_resolve_via_unification_table(impl_args);
168 }
169 inspect::ProbeStep::AddGoal(..) => {}
170 inspect::ProbeStep::MakeCanonicalResponse { .. }
171 | inspect::ProbeStep::NestedProbe(_) => unreachable!(),
172 }
173 }
174
175 bug!("expected impl args probe step for `instantiate_impl_args`");
176 }
177
178 pub fn instantiate_proof_tree_for_nested_goal(
179 &self,
180 source: GoalSource,
181 goal: Goal<'tcx, ty::Predicate<'tcx>>,
182 span: Span,
183 ) -> InspectGoal<'a, 'tcx> {
184 let infcx = self.goal.infcx;
185 match goal.predicate.kind().no_bound_vars() {
186 Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { .. })) => {
187 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
189 }
190 _ => {
191 let proof_tree =
197 infcx.probe(|_| infcx.evaluate_root_goal_for_proof_tree(goal, span).1);
198 InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, source)
199 }
200 }
201 }
202
203 pub fn visit_nested_in_probe<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
206 self.goal.infcx.probe(|_| self.visit_nested_no_probe(visitor))
207 }
208}
209
210impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
211 pub fn infcx(&self) -> &'a InferCtxt<'tcx> {
212 self.infcx
213 }
214
215 pub fn goal(&self) -> Goal<'tcx, ty::Predicate<'tcx>> {
216 self.goal
217 }
218
219 pub fn result(&self) -> Result<Certainty, NoSolution> {
220 self.result
221 }
222
223 pub fn source(&self) -> GoalSource {
224 self.source
225 }
226
227 pub fn depth(&self) -> usize {
228 self.depth
229 }
230
231 pub fn required_depth(&self) -> RequiredDepth {
232 self.required_depth
233 }
234
235 pub fn orig_values(&self) -> &[ty::GenericArg<'tcx>] {
236 &self.orig_values
237 }
238
239 fn candidates_recur(
240 &'a self,
241 candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,
242 steps: &mut Vec<&'a inspect::ProbeStep<TyCtxt<'tcx>>>,
243 probe: &'a inspect::Probe<TyCtxt<'tcx>>,
244 ) {
245 let mut shallow_certainty = None;
246 for step in &probe.steps {
247 match *step {
248 inspect::ProbeStep::AddGoal(..) | inspect::ProbeStep::RecordImplArgs { .. } => {
249 steps.push(step)
250 }
251 inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
252 {
match shallow_certainty.replace(c) {
None |
Some(Certainty::Maybe(MaybeInfo {
cause: MaybeCause::Ambiguity,
opaque_types_jank: _,
stalled_on_coroutines: _ })) => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val,
"None |\nSome(Certainty::Maybe(MaybeInfo\n{\n cause: MaybeCause::Ambiguity, opaque_types_jank: _, stalled_on_coroutines:\n _,\n}))",
::core::option::Option::None);
}
}
};assert_matches!(
253 shallow_certainty.replace(c),
254 None | Some(Certainty::Maybe(MaybeInfo {
255 cause: MaybeCause::Ambiguity,
256 opaque_types_jank: _,
257 stalled_on_coroutines: _,
258 }))
259 );
260 }
261 inspect::ProbeStep::NestedProbe(ref probe) => {
262 match probe.kind {
263 inspect::ProbeKind::ProjectionCompatibility
265 | inspect::ProbeKind::ShadowedEnvProbing => continue,
266
267 inspect::ProbeKind::NormalizedSelfTyAssembly
268 | inspect::ProbeKind::UnsizeAssembly
269 | inspect::ProbeKind::Root { .. }
270 | inspect::ProbeKind::TraitCandidate { .. }
271 | inspect::ProbeKind::OpaqueTypeStorageLookup { .. }
272 | inspect::ProbeKind::RigidAlias { .. } => {
273 let num_steps = steps.len();
277 self.candidates_recur(candidates, steps, probe);
278 steps.truncate(num_steps);
279 }
280 }
281 }
282 }
283 }
284
285 match probe.kind {
286 inspect::ProbeKind::ProjectionCompatibility
287 | inspect::ProbeKind::ShadowedEnvProbing => {
288 ::rustc_span::macros::bug_impl(None, format_args!("impossible case reached"),
Location::caller())bug!()
289 }
290
291 inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {}
292
293 inspect::ProbeKind::Root { result }
296 | inspect::ProbeKind::TraitCandidate { source: _, result }
297 | inspect::ProbeKind::OpaqueTypeStorageLookup { result }
298 | inspect::ProbeKind::RigidAlias { result } => {
299 if let Some(shallow_certainty) = shallow_certainty {
302 candidates.push(InspectCandidate {
303 goal: self,
304 kind: probe.kind,
305 steps: steps.clone(),
306 final_state: probe.final_state,
307 shallow_certainty,
308 result,
309 });
310 }
311 }
312 }
313 }
314
315 pub fn candidates(&'a self) -> Vec<InspectCandidate<'a, 'tcx>> {
316 let mut candidates = ::alloc::vec::Vec::new()vec![];
317 let mut nested_goals = ::alloc::vec::Vec::new()vec![];
318 self.candidates_recur(&mut candidates, &mut nested_goals, &self.final_revision);
319 candidates
320 }
321
322 pub fn unique_applicable_candidate(&'a self) -> Option<InspectCandidate<'a, 'tcx>> {
326 let mut candidates = self.candidates();
329 candidates.retain(|c| c.result().is_ok());
330 candidates.pop().filter(|_| candidates.is_empty())
331 }
332
333 fn new(
334 infcx: &'a InferCtxt<'tcx>,
335 depth: usize,
336 root: inspect::GoalEvaluation<TyCtxt<'tcx>>,
337 source: GoalSource,
338 ) -> Self {
339 let infcx = <&SolverDelegate<'tcx>>::from(infcx);
340 let prev_universe = infcx.universe();
341
342 let inspect::GoalEvaluation {
343 uncanonicalized_goal,
344 orig_values,
345 final_revision,
346 result,
347 required_depth,
348 } = root;
349 let result = result.map(|ok| ok.value.certainty);
352
353 InspectGoal {
354 infcx,
355 depth,
356 orig_values,
357 prev_universe,
358 goal: infcx.deeply_resolve_via_unification_table(uncanonicalized_goal),
359 result,
360 final_revision,
361 source,
362 required_depth,
363 }
364 }
365
366 pub(crate) fn visit_with<V: ProofTreeVisitor<'tcx>>(&self, visitor: &mut V) -> V::Result {
367 if self.depth < visitor.config().max_depth {
368 match ::rustc_ast_ir::visit::VisitorResult::branch(visitor.visit_goal(self)) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(visitor.visit_goal(self));
369 V::Result::output()
370 } else {
371 visitor.on_recursion_limit()
372 }
373 }
374}
375
376pub trait ProofTreeVisitor<'tcx> {
378 type Result: VisitorResult = ();
379
380 fn span(&self) -> Span;
381
382 fn config(&self) -> InspectConfig {
383 InspectConfig { max_depth: 10 }
384 }
385
386 fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> Self::Result;
387
388 fn on_recursion_limit(&mut self) -> Self::Result {
389 Self::Result::output()
390 }
391}
392
393pub trait InferCtxtProofTreeExt<'tcx> {
fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, visitor: &mut V)
-> V::Result;
fn visit_proof_tree_at_depth<V: ProofTreeVisitor<'tcx>>(&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, depth: usize, visitor: &mut V)
-> V::Result;
}
impl<'tcx> InferCtxtProofTreeExt<'tcx> for InferCtxt<'tcx> {
fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, visitor: &mut V) -> V::Result {
self.visit_proof_tree_at_depth(goal, 0, visitor)
}
fn visit_proof_tree_at_depth<V: ProofTreeVisitor<'tcx>>(&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>, depth: usize, visitor: &mut V)
-> V::Result {
let (_, proof_tree) =
<&SolverDelegate<'tcx>>::from(self).evaluate_root_goal_for_proof_tree(goal,
visitor.span());
visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree,
GoalSource::Misc))
}
}#[extension(pub trait InferCtxtProofTreeExt<'tcx>)]
394impl<'tcx> InferCtxt<'tcx> {
395 fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(
396 &self,
397 goal: Goal<'tcx, ty::Predicate<'tcx>>,
398 visitor: &mut V,
399 ) -> V::Result {
400 self.visit_proof_tree_at_depth(goal, 0, visitor)
401 }
402
403 fn visit_proof_tree_at_depth<V: ProofTreeVisitor<'tcx>>(
404 &self,
405 goal: Goal<'tcx, ty::Predicate<'tcx>>,
406 depth: usize,
407 visitor: &mut V,
408 ) -> V::Result {
409 let (_, proof_tree) = <&SolverDelegate<'tcx>>::from(self)
410 .evaluate_root_goal_for_proof_tree(goal, visitor.span());
411 visitor.visit_goal(&InspectGoal::new(self, depth, proof_tree, GoalSource::Misc))
412 }
413}