1use std::ops::ControlFlow;
2
3use rustc_hir::LangItem;
4use rustc_infer::infer::InferCtxt;
5use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
6use rustc_infer::traits::{
7 self, MismatchedProjectionTypes, Obligation, ObligationCause, ObligationCauseCode,
8 PredicateObligation, SelectionError,
9};
10use rustc_middle::traits::query::NoSolution;
11use rustc_middle::ty::error::{ExpectedFound, TypeError};
12use rustc_middle::ty::{self, Ty, TyCtxt};
13use rustc_middle::{bug, span_bug};
14use rustc_next_trait_solver::solve::{GoalEvaluation, MaybeInfo, SolverDelegateEvalExt as _};
15use tracing::{instrument, trace};
16
17use crate::solve::delegate::SolverDelegate;
18use crate::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
19use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
20use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
21
22pub(super) fn fulfillment_error_for_no_solution<'tcx>(
23 infcx: &InferCtxt<'tcx>,
24 root_obligation: PredicateObligation<'tcx>,
25) -> FulfillmentError<'tcx> {
26 let obligation = find_best_leaf_obligation(infcx, &root_obligation, false);
27
28 let code = match obligation.predicate.kind().skip_binder() {
29 ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
30 FulfillmentErrorCode::Project(
31 MismatchedProjectionTypes { err: TypeError::Mismatch },
33 )
34 }
35 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, expected_ty)) => {
36 let ct_ty = match ct.kind() {
37 ty::ConstKind::Alias(_, alias_const) => {
38 alias_const.type_of(infcx.tcx).skip_norm_wip()
39 }
40 ty::ConstKind::Param(param_ct) => {
41 param_ct.find_const_ty_from_env(obligation.param_env)
42 }
43 ty::ConstKind::Value(cv) => cv.ty,
44 kind => ::rustc_middle::util::bug::span_bug_fmt(obligation.cause.span,
format_args!("ConstArgHasWrongType failed but we don\'t know how to compute type for {0:?}",
kind))span_bug!(
45 obligation.cause.span,
46 "ConstArgHasWrongType failed but we don't know how to compute type for {kind:?}"
47 ),
48 };
49 FulfillmentErrorCode::Select(SelectionError::ConstArgHasWrongType {
50 ct,
51 ct_ty,
52 expected_ty,
53 })
54 }
55 ty::PredicateKind::Subtype(pred) => {
56 let (a, b) = infcx.enter_forall_and_leak_universe(
57 obligation.predicate.kind().rebind((pred.a, pred.b)),
58 );
59 let expected_found = ExpectedFound::new(a, b);
60 FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
61 }
62 ty::PredicateKind::Coerce(pred) => {
63 let (a, b) = infcx.enter_forall_and_leak_universe(
64 obligation.predicate.kind().rebind((pred.a, pred.b)),
65 );
66 let expected_found = ExpectedFound::new(b, a);
67 FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
68 }
69 ty::PredicateKind::Clause(_)
70 | ty::PredicateKind::DynCompatible(_)
71 | ty::PredicateKind::Ambiguous => {
72 FulfillmentErrorCode::Select(SelectionError::Unimplemented)
73 }
74 ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::NormalizesTo(..) => {
75 ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected goal: {0:?}",
obligation))bug!("unexpected goal: {obligation:?}")
76 }
77 };
78
79 FulfillmentError { obligation, code, root_obligation }
80}
81
82pub(super) fn fulfillment_error_for_stalled<'tcx>(
83 infcx: &InferCtxt<'tcx>,
84 root_obligation: PredicateObligation<'tcx>,
85) -> FulfillmentError<'tcx> {
86 let (code, refine_obligation) = infcx.probe(|_| {
87 match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
88 root_obligation.as_goal(),
89 root_obligation.cause.span,
90 None,
91 ) {
92 Ok(GoalEvaluation {
93 certainty:
94 Certainty::Maybe(MaybeInfo {
95 cause: MaybeCause::Ambiguity,
96 opaque_types_jank: _,
97 stalled_on_coroutines: _,
98 }),
99 ..
100 }) => (FulfillmentErrorCode::Ambiguity { overflow: None }, true),
101 Ok(GoalEvaluation {
102 certainty:
103 Certainty::Maybe(MaybeInfo {
104 cause:
105 MaybeCause::Overflow { suggest_increasing_limit, keep_constraints: _ },
106 opaque_types_jank: _,
107 stalled_on_coroutines: _,
108 }),
109 ..
110 }) => (
111 FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
112 false,
119 ),
120 Ok(GoalEvaluation { certainty: Certainty::Yes, .. }) => {
121 ::rustc_middle::util::bug::span_bug_fmt(root_obligation.cause.span,
format_args!("did not expect successful goal when collecting ambiguity errors for `{0:?}`",
infcx.resolve_vars_if_possible(root_obligation.predicate)))span_bug!(
122 root_obligation.cause.span,
123 "did not expect successful goal when collecting ambiguity errors for `{:?}`",
124 infcx.resolve_vars_if_possible(root_obligation.predicate),
125 )
126 }
127 Err(_) => {
128 ::rustc_middle::util::bug::span_bug_fmt(root_obligation.cause.span,
format_args!("did not expect selection error when collecting ambiguity errors for `{0:?}`",
infcx.resolve_vars_if_possible(root_obligation.predicate)))span_bug!(
129 root_obligation.cause.span,
130 "did not expect selection error when collecting ambiguity errors for `{:?}`",
131 infcx.resolve_vars_if_possible(root_obligation.predicate),
132 )
133 }
134 }
135 });
136
137 FulfillmentError {
138 obligation: if refine_obligation {
139 find_best_leaf_obligation(infcx, &root_obligation, true)
140 } else {
141 root_obligation.clone()
142 },
143 code,
144 root_obligation,
145 }
146}
147
148pub(super) fn fulfillment_error_for_overflow<'tcx>(
149 infcx: &InferCtxt<'tcx>,
150 root_obligation: PredicateObligation<'tcx>,
151) -> FulfillmentError<'tcx> {
152 FulfillmentError {
153 obligation: find_best_leaf_obligation(infcx, &root_obligation, true),
154 code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) },
155 root_obligation,
156 }
157}
158
159x;#[instrument(level = "debug", skip(infcx), ret)]
160fn find_best_leaf_obligation<'tcx>(
161 infcx: &InferCtxt<'tcx>,
162 obligation: &PredicateObligation<'tcx>,
163 consider_ambiguities: bool,
164) -> PredicateObligation<'tcx> {
165 let obligation = infcx.resolve_vars_if_possible(obligation.clone());
166 let obligation = infcx
172 .fudge_inference_if_ok(|| {
173 infcx
174 .visit_proof_tree(
175 obligation.as_goal(),
176 &mut BestObligation { obligation: obligation.clone(), consider_ambiguities },
177 )
178 .break_value()
179 .ok_or(())
180 .map(|o| (o.cause.clone(), o))
183 })
184 .map(|(cause, o)| PredicateObligation { cause, ..o })
185 .unwrap_or(obligation);
186 deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation)
187}
188
189struct BestObligation<'tcx> {
190 obligation: PredicateObligation<'tcx>,
191 consider_ambiguities: bool,
192}
193
194impl<'tcx> BestObligation<'tcx> {
195 fn with_derived_obligation(
196 &mut self,
197 derived_obligation: PredicateObligation<'tcx>,
198 and_then: impl FnOnce(&mut Self) -> <Self as ProofTreeVisitor<'tcx>>::Result,
199 ) -> <Self as ProofTreeVisitor<'tcx>>::Result {
200 let old_obligation = std::mem::replace(&mut self.obligation, derived_obligation);
201 let res = and_then(self);
202 self.obligation = old_obligation;
203 res
204 }
205
206 fn non_trivial_candidates<'a>(
211 &self,
212 goal: &'a inspect::InspectGoal<'a, 'tcx>,
213 ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> {
214 let mut candidates = goal.candidates();
215 match self.consider_ambiguities {
216 true => {
217 candidates.retain(|candidate| candidate.result().is_ok());
221 }
222 false => {
223 candidates.retain(|c| !#[allow(non_exhaustive_omitted_patterns)] match c.kind() {
inspect::ProbeKind::RigidAlias { .. } => true,
_ => false,
}matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. }));
226 if candidates.len() > 1 {
230 candidates.retain(|candidate| {
231 goal.infcx().probe(|_| {
232 candidate.instantiate_nested_goals(self.span()).iter().any(
233 |nested_goal| {
234 #[allow(non_exhaustive_omitted_patterns)] match nested_goal.source() {
GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition |
GoalSource::AliasWellFormed => true,
_ => false,
}matches!(
235 nested_goal.source(),
236 GoalSource::ImplWhereBound
237 | GoalSource::AliasBoundConstCondition
238 | GoalSource::AliasWellFormed
239 ) && nested_goal.result().is_err()
240 },
241 )
242 })
243 });
244 }
245 }
246 }
247
248 candidates
249 }
250
251 fn visit_well_formed_goal(
255 &mut self,
256 candidate: &inspect::InspectCandidate<'_, 'tcx>,
257 term: ty::Term<'tcx>,
258 ) -> ControlFlow<PredicateObligation<'tcx>> {
259 let infcx = candidate.goal().infcx();
260 let param_env = candidate.goal().goal().param_env;
261 let body_id = self.obligation.cause.body_id;
262
263 for obligation in wf::unnormalized_obligations(infcx, param_env, term, self.span(), body_id)
264 .into_flat_iter()
265 {
266 let nested_goal = candidate.instantiate_proof_tree_for_nested_goal(
267 GoalSource::Misc,
268 obligation.as_goal(),
269 self.span(),
270 );
271 match (self.consider_ambiguities, nested_goal.result()) {
273 (
274 true,
275 Ok(Certainty::Maybe(MaybeInfo {
276 cause: MaybeCause::Ambiguity,
277 opaque_types_jank: _,
278 stalled_on_coroutines: _,
279 })),
280 )
281 | (false, Err(_)) => {}
282 _ => continue,
283 }
284
285 self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
286 }
287
288 ControlFlow::Break(self.obligation.clone())
289 }
290
291 fn detect_error_in_self_ty_normalization(
295 &mut self,
296 goal: &inspect::InspectGoal<'_, 'tcx>,
297 self_ty: Ty<'tcx>,
298 ) -> ControlFlow<PredicateObligation<'tcx>> {
299 if !!self.consider_ambiguities {
::core::panicking::panic("assertion failed: !self.consider_ambiguities")
};assert!(!self.consider_ambiguities);
300 let tcx = goal.infcx().tcx;
301 if let ty::Alias(_, alias) = *self_ty.kind() {
302 let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span);
303 let pred =
304 ty::ProjectionPredicate { projection_term: alias.into(), term: infer_term.into() };
305 let obligation =
306 Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred);
307 self.with_derived_obligation(obligation, |this| {
308 goal.infcx().visit_proof_tree_at_depth(
309 goal.goal().with(tcx, pred),
310 goal.depth() + 1,
311 this,
312 )
313 })
314 } else {
315 ControlFlow::Continue(())
316 }
317 }
318
319 fn detect_trait_error_in_higher_ranked_projection(
327 &mut self,
328 goal: &inspect::InspectGoal<'_, 'tcx>,
329 ) -> ControlFlow<PredicateObligation<'tcx>> {
330 let tcx = goal.infcx().tcx;
331 if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
332 && !projection_clause.bound_vars().is_empty()
333 {
334 let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
335 let obligation = Obligation::new(
336 tcx,
337 self.obligation.cause.clone(),
338 goal.goal().param_env,
339 deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
340 );
341 self.with_derived_obligation(obligation, |this| {
342 goal.infcx().visit_proof_tree_at_depth(
343 goal.goal().with(tcx, pred),
344 goal.depth() + 1,
345 this,
346 )
347 })
348 } else {
349 ControlFlow::Continue(())
350 }
351 }
352
353 fn detect_non_well_formed_assoc_item(
360 &mut self,
361 goal: &inspect::InspectGoal<'_, 'tcx>,
362 alias: ty::AliasTerm<'tcx>,
363 ) -> ControlFlow<PredicateObligation<'tcx>> {
364 let tcx = goal.infcx().tcx;
365 let obligation = Obligation::new(
366 tcx,
367 self.obligation.cause.clone(),
368 goal.goal().param_env,
369 alias.trait_ref(tcx),
370 );
371 self.with_derived_obligation(obligation, |this| {
372 goal.infcx().visit_proof_tree_at_depth(
373 goal.goal().with(tcx, alias.trait_ref(tcx)),
374 goal.depth() + 1,
375 this,
376 )
377 })
378 }
379
380 fn detect_error_from_empty_candidates(
383 &mut self,
384 goal: &inspect::InspectGoal<'_, 'tcx>,
385 ) -> ControlFlow<PredicateObligation<'tcx>> {
386 let pred_kind = goal.goal().predicate.kind();
387
388 match pred_kind.no_bound_vars() {
389 Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => {
390 self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
391 }
392 Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)))
393 if pred.projection_term.kind.is_trait_projection() =>
394 {
395 self.detect_error_in_self_ty_normalization(goal, pred.projection_term.self_ty())?;
396 self.detect_non_well_formed_assoc_item(goal, pred.projection_term)?;
397 }
398 Some(_) | None => {}
399 }
400
401 ControlFlow::Break(self.obligation.clone())
402 }
403}
404
405impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
406 type Result = ControlFlow<PredicateObligation<'tcx>>;
407
408 fn span(&self) -> rustc_span::Span {
409 self.obligation.cause.span
410 }
411
412 #[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("visit_goal",
"rustc_trait_selection::solve::fulfill::derive_errors",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs"),
::tracing_core::__macro_support::Option::Some(412u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::fulfill::derive_errors"),
::tracing_core::field::FieldSet::new(&["goal"],
::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(&debug(&goal.goal())
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: Self::Result = loop {};
return __tracing_attr_fake_return;
}
{
let tcx = goal.infcx().tcx;
match (self.consider_ambiguities, goal.result()) {
(true,
Ok(Certainty::Maybe(MaybeInfo {
cause: MaybeCause::Ambiguity,
opaque_types_jank: _,
stalled_on_coroutines: _ }))) | (false, Err(_)) => {}
_ => return ControlFlow::Continue(()),
}
let pred = goal.goal().predicate;
let candidates = self.non_trivial_candidates(goal);
let candidate =
match candidates.as_slice() {
[candidate] => candidate,
[] => return self.detect_error_from_empty_candidates(goal),
_ => return ControlFlow::Break(self.obligation.clone()),
};
if let inspect::ProbeKind::TraitCandidate {
source: CandidateSource::Impl(impl_def_id), result: _ } =
candidate.kind() && tcx.do_not_recommend_impl(impl_def_id) {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs:445",
"rustc_trait_selection::solve::fulfill::derive_errors",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs"),
::tracing_core::__macro_support::Option::Some(445u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::fulfill::derive_errors"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("#[diagnostic::do_not_recommend] -> exit")
as &dyn Value))])
});
} else { ; }
};
return ControlFlow::Break(self.obligation.clone());
}
let child_mode =
match pred.kind().skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))
=> {
ChildMode::Trait(pred.kind().rebind(trait_pred))
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(host_pred))
=> {
ChildMode::Host(pred.kind().rebind(host_pred))
}
ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection))
if projection.projection_term.kind.is_trait_projection() =>
{
ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate {
trait_ref: projection.projection_term.trait_ref(tcx),
polarity: ty::PredicatePolarity::Positive,
}))
}
ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term))
=> {
return self.visit_well_formed_goal(candidate, term);
}
_ => ChildMode::PassThrough,
};
let nested_goals =
candidate.instantiate_nested_goals(self.span());
for nested_goal in &nested_goals {
if let Some(poly_trait_pred) =
nested_goal.goal().predicate.as_trait_clause() &&
tcx.is_lang_item(poly_trait_pred.def_id(),
LangItem::FnPtrTrait) &&
let Err(NoSolution) = nested_goal.result() {
return ControlFlow::Break(self.obligation.clone());
}
}
let mut impl_where_bound_count = 0;
for nested_goal in nested_goals {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs:492",
"rustc_trait_selection::solve::fulfill::derive_errors",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs"),
::tracing_core::__macro_support::Option::Some(492u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::solve::fulfill::derive_errors"),
::tracing_core::field::FieldSet::new(&["nested_goal"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&(nested_goal.goal(),
nested_goal.source(), nested_goal.result())) as
&dyn Value))])
});
} else { ; }
};
let nested_pred = nested_goal.goal().predicate;
let make_obligation =
|cause|
Obligation {
cause,
param_env: nested_goal.goal().param_env,
predicate: nested_pred,
recursion_depth: self.obligation.recursion_depth + 1,
};
let obligation;
match (child_mode, nested_goal.source()) {
(ChildMode::Trait(_) | ChildMode::Host(_),
GoalSource::Misc | GoalSource::TypeRelating |
GoalSource::NormalizeGoal(_)) => {
continue;
}
(ChildMode::Trait(parent_trait_pred),
GoalSource::ImplWhereBound) => {
obligation =
make_obligation(derive_cause(tcx, candidate.kind(),
self.obligation.cause.clone(), impl_where_bound_count,
parent_trait_pred));
impl_where_bound_count += 1;
}
(ChildMode::Host(parent_host_pred),
GoalSource::ImplWhereBound |
GoalSource::AliasBoundConstCondition) => {
obligation =
make_obligation(derive_host_cause(tcx, candidate.kind(),
self.obligation.cause.clone(), impl_where_bound_count,
parent_host_pred));
impl_where_bound_count += 1;
}
(ChildMode::PassThrough, _) |
(_,
GoalSource::AliasWellFormed |
GoalSource::AliasBoundConstCondition) => {
obligation = make_obligation(self.obligation.cause.clone());
}
}
self.with_derived_obligation(obligation,
|this| nested_goal.visit_with(this))?;
}
self.detect_trait_error_in_higher_ranked_projection(goal)?;
ControlFlow::Break(self.obligation.clone())
}
}
}#[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
413 fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
414 let tcx = goal.infcx().tcx;
415 match (self.consider_ambiguities, goal.result()) {
417 (
418 true,
419 Ok(Certainty::Maybe(MaybeInfo {
420 cause: MaybeCause::Ambiguity,
421 opaque_types_jank: _,
422 stalled_on_coroutines: _,
423 })),
424 )
425 | (false, Err(_)) => {}
426 _ => return ControlFlow::Continue(()),
427 }
428
429 let pred = goal.goal().predicate;
430
431 let candidates = self.non_trivial_candidates(goal);
432 let candidate = match candidates.as_slice() {
433 [candidate] => candidate,
434 [] => return self.detect_error_from_empty_candidates(goal),
435 _ => return ControlFlow::Break(self.obligation.clone()),
436 };
437
438 if let inspect::ProbeKind::TraitCandidate {
440 source: CandidateSource::Impl(impl_def_id),
441 result: _,
442 } = candidate.kind()
443 && tcx.do_not_recommend_impl(impl_def_id)
444 {
445 trace!("#[diagnostic::do_not_recommend] -> exit");
446 return ControlFlow::Break(self.obligation.clone());
447 }
448
449 let child_mode = match pred.kind().skip_binder() {
452 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
453 ChildMode::Trait(pred.kind().rebind(trait_pred))
454 }
455 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(host_pred)) => {
456 ChildMode::Host(pred.kind().rebind(host_pred))
457 }
458 ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection))
459 if projection.projection_term.kind.is_trait_projection() =>
460 {
461 ChildMode::Trait(pred.kind().rebind(ty::TraitPredicate {
462 trait_ref: projection.projection_term.trait_ref(tcx),
463 polarity: ty::PredicatePolarity::Positive,
464 }))
465 }
466 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
467 return self.visit_well_formed_goal(candidate, term);
468 }
469 _ => ChildMode::PassThrough,
470 };
471
472 let nested_goals = candidate.instantiate_nested_goals(self.span());
473
474 for nested_goal in &nested_goals {
482 if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
483 && tcx.is_lang_item(poly_trait_pred.def_id(), LangItem::FnPtrTrait)
484 && let Err(NoSolution) = nested_goal.result()
485 {
486 return ControlFlow::Break(self.obligation.clone());
487 }
488 }
489
490 let mut impl_where_bound_count = 0;
491 for nested_goal in nested_goals {
492 trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
493
494 let nested_pred = nested_goal.goal().predicate;
495
496 let make_obligation = |cause| Obligation {
497 cause,
498 param_env: nested_goal.goal().param_env,
499 predicate: nested_pred,
500 recursion_depth: self.obligation.recursion_depth + 1,
501 };
502
503 let obligation;
504 match (child_mode, nested_goal.source()) {
505 (
506 ChildMode::Trait(_) | ChildMode::Host(_),
507 GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_),
508 ) => {
509 continue;
510 }
511 (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
512 obligation = make_obligation(derive_cause(
513 tcx,
514 candidate.kind(),
515 self.obligation.cause.clone(),
516 impl_where_bound_count,
517 parent_trait_pred,
518 ));
519 impl_where_bound_count += 1;
520 }
521 (
522 ChildMode::Host(parent_host_pred),
523 GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition,
524 ) => {
525 obligation = make_obligation(derive_host_cause(
526 tcx,
527 candidate.kind(),
528 self.obligation.cause.clone(),
529 impl_where_bound_count,
530 parent_host_pred,
531 ));
532 impl_where_bound_count += 1;
533 }
534 (ChildMode::PassThrough, _)
535 | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => {
536 obligation = make_obligation(self.obligation.cause.clone());
537 }
538 }
539
540 self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
541 }
542
543 self.detect_trait_error_in_higher_ranked_projection(goal)?;
544
545 ControlFlow::Break(self.obligation.clone())
546 }
547}
548
549#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ChildMode<'tcx> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
ChildMode::Trait(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Trait",
&__self_0),
ChildMode::Host(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Host",
&__self_0),
ChildMode::PassThrough =>
::core::fmt::Formatter::write_str(f, "PassThrough"),
}
}
}Debug, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for ChildMode<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for ChildMode<'tcx> {
#[inline]
fn clone(&self) -> ChildMode<'tcx> {
let _:
::core::clone::AssertParamIsClone<ty::PolyTraitPredicate<'tcx>>;
let _:
::core::clone::AssertParamIsClone<ty::Binder<'tcx,
ty::HostEffectPredicate<'tcx>>>;
*self
}
}Clone)]
550enum ChildMode<'tcx> {
551 Trait(ty::PolyTraitPredicate<'tcx>),
555 Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
559 PassThrough,
563}
564
565fn derive_cause<'tcx>(
566 tcx: TyCtxt<'tcx>,
567 candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
568 mut cause: ObligationCause<'tcx>,
569 idx: usize,
570 parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
571) -> ObligationCause<'tcx> {
572 match candidate_kind {
573 inspect::ProbeKind::TraitCandidate {
574 source: CandidateSource::Impl(impl_def_id),
575 result: _,
576 } => {
577 if let Some((_, span)) =
578 tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
579 {
580 cause = cause.derived_cause(parent_trait_pred, |derived| {
581 ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
582 derived,
583 impl_or_alias_def_id: impl_def_id,
584 impl_def_predicate_index: Some(idx),
585 span,
586 }))
587 })
588 }
589 }
590 inspect::ProbeKind::TraitCandidate {
591 source: CandidateSource::BuiltinImpl(..),
592 result: _,
593 } => {
594 cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived);
595 }
596 _ => {}
597 };
598 cause
599}
600
601fn derive_host_cause<'tcx>(
602 tcx: TyCtxt<'tcx>,
603 candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
604 mut cause: ObligationCause<'tcx>,
605 idx: usize,
606 parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
607) -> ObligationCause<'tcx> {
608 match candidate_kind {
609 inspect::ProbeKind::TraitCandidate {
610 source: CandidateSource::Impl(impl_def_id),
611 result: _,
612 } => {
613 if let Some((_, span)) = tcx
614 .predicates_of(impl_def_id)
615 .instantiate_identity(tcx)
616 .into_iter()
617 .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
618 |(trait_ref, span)| {
619 (
620 trait_ref.to_host_effect_clause(
621 tcx,
622 parent_host_pred.skip_binder().constness,
623 ),
624 span,
625 )
626 },
627 ))
628 .nth(idx)
629 {
630 cause =
631 cause.derived_host_cause(parent_host_pred, |derived| {
632 ObligationCauseCode::ImplDerivedHost(Box::new(
633 traits::ImplDerivedHostCause { derived, impl_def_id, span },
634 ))
635 })
636 }
637 }
638 inspect::ProbeKind::TraitCandidate {
639 source: CandidateSource::BuiltinImpl(..),
640 result: _,
641 } => {
642 cause =
643 cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
644 }
645 _ => {}
646 };
647 cause
648}