Add derived causes for host effect predicates

This commit is contained in:
Michael Goulet 2024-12-10 22:08:44 +00:00
parent 243d2ca4db
commit 2be9ffc1af
15 changed files with 278 additions and 39 deletions

View file

@ -753,7 +753,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
applied_do_not_recommend = true;
}
}
if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
if let Some(parent_cause) = base_cause.parent() {
base_cause = parent_cause.clone();
} else {
break;
@ -778,7 +778,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
&& !found_kind.extends(expected_kind)
{
if let Some((_, Some(parent))) = obligation.cause.code().parent() {
if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
trait_ref = parent.to_poly_trait_ref();
} else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
@ -926,7 +926,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let Some(typeck) = &self.typeck_results else {
return false;
};
let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent()
let Some((ObligationCauseCode::QuestionMark, Some(y))) =
obligation.cause.code().parent_with_predicate()
else {
return false;
};
@ -1179,7 +1180,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut code = obligation.cause.code();
let mut pred = obligation.predicate.as_trait_clause();
while let Some((next_code, next_pred)) = code.parent() {
while let Some((next_code, next_pred)) = code.parent_with_predicate() {
if let Some(pred) = pred {
self.enter_forall(pred, |pred| {
diag.note(format!(
@ -2095,7 +2096,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut code = obligation.cause.code();
let mut trait_pred = trait_predicate;
let mut peeled = false;
while let Some((parent_code, parent_trait_pred)) = code.parent() {
while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
code = parent_code;
if let Some(parent_trait_pred) = parent_trait_pred {
trait_pred = parent_trait_pred;

View file

@ -464,7 +464,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// Get the root obligation, since the leaf obligation we have may be unhelpful (#87437)
let mut real_trait_pred = trait_pred;
while let Some((parent_code, parent_trait_pred)) = code.parent() {
while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
code = parent_code;
if let Some(parent_trait_pred) = parent_trait_pred {
real_trait_pred = parent_trait_pred;
@ -1447,7 +1447,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut span = obligation.cause.span;
let mut trait_pred = trait_pred;
let mut code = obligation.cause.code();
while let Some((c, Some(parent_trait_pred))) = code.parent() {
while let Some((c, Some(parent_trait_pred))) = code.parent_with_predicate() {
// We want the root obligation, in order to detect properly handle
// `for _ in &mut &mut vec![] {}`.
code = c;
@ -3470,6 +3470,59 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
)
});
}
ObligationCauseCode::ImplDerivedHost(ref data) => {
let self_ty =
self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty());
let msg = format!(
"required for `{self_ty}` to implement `{} {}`",
data.derived.parent_host_pred.skip_binder().constness,
data.derived
.parent_host_pred
.map_bound(|pred| pred.trait_ref)
.print_only_trait_path(),
);
match tcx.hir().get_if_local(data.impl_def_id) {
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
})) => {
let mut spans = vec![self_ty.span];
spans.extend(of_trait.as_ref().map(|t| t.path.span));
let mut spans: MultiSpan = spans.into();
spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
err.span_note(spans, msg);
}
_ => {
err.note(msg);
}
}
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
body_id,
err,
data.derived.parent_host_pred,
param_env,
&data.derived.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
ObligationCauseCode::BuiltinDerivedHost(ref data) => {
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
body_id,
err,
data.parent_host_pred,
param_env,
&data.parent_code,
obligated_types,
seen_requirements,
long_ty_file,
)
});
}
ObligationCauseCode::WellFormedDerived(ref data) => {
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
let parent_predicate = parent_trait_ref;

View file

@ -474,8 +474,11 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
// for normalizes-to.
let pred_kind = goal.goal().predicate.kind();
let child_mode = match pred_kind.skip_binder() {
ty::PredicateKind::Clause(ty::ClauseKind::Trait(parent_trait_pred)) => {
ChildMode::Trait(pred_kind.rebind(parent_trait_pred))
ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
ChildMode::Trait(pred_kind.rebind(pred))
}
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => {
ChildMode::Host(pred_kind.rebind(pred))
}
ty::PredicateKind::NormalizesTo(normalizes_to)
if matches!(
@ -492,6 +495,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
};
let mut impl_where_bound_count = 0;
let mut impl_const_condition_bound_count = 0;
for nested_goal in candidate.instantiate_nested_goals(self.span()) {
trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
@ -504,7 +508,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
let obligation;
match (child_mode, nested_goal.source()) {
(ChildMode::Trait(_), GoalSource::Misc) => {
(ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => {
continue;
}
(ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
@ -517,6 +521,16 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
));
impl_where_bound_count += 1;
}
(ChildMode::Host(parent_host_pred), GoalSource::ImplWhereBound) => {
obligation = make_obligation(derive_host_cause(
tcx,
candidate.kind(),
self.obligation.cause.clone(),
impl_const_condition_bound_count,
parent_host_pred,
));
impl_const_condition_bound_count += 1;
}
// Skip over a higher-ranked predicate.
(_, GoalSource::InstantiateHigherRanked) => {
obligation = self.obligation.clone();
@ -575,6 +589,10 @@ enum ChildMode<'tcx> {
// and skip all `GoalSource::Misc`, which represent useless obligations
// such as alias-eq which may not hold.
Trait(ty::PolyTraitPredicate<'tcx>),
// Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
// and skip all `GoalSource::Misc`, which represent useless obligations
// such as alias-eq which may not hold.
Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
// Skip trying to derive an `ObligationCause` from this obligation, and
// report *all* sub-obligations as if they came directly from the parent
// obligation.
@ -616,3 +634,52 @@ fn derive_cause<'tcx>(
};
cause
}
fn derive_host_cause<'tcx>(
tcx: TyCtxt<'tcx>,
candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
mut cause: ObligationCause<'tcx>,
idx: usize,
parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
) -> ObligationCause<'tcx> {
match candidate_kind {
inspect::ProbeKind::TraitCandidate {
source: CandidateSource::Impl(impl_def_id),
result: _,
} => {
if let Some((_, span)) = tcx
.predicates_of(impl_def_id)
.instantiate_identity(tcx)
.into_iter()
.chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
|(trait_ref, span)| {
(
trait_ref.to_host_effect_clause(
tcx,
parent_host_pred.skip_binder().constness,
),
span,
)
},
))
.nth(idx)
{
cause =
cause.derived_host_cause(parent_host_pred, |derived| {
ObligationCauseCode::ImplDerivedHost(Box::new(
traits::ImplDerivedHostCause { derived, impl_def_id, span },
))
})
}
}
inspect::ProbeKind::TraitCandidate {
source: CandidateSource::BuiltinImpl(..),
result: _,
} => {
cause =
cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
}
_ => {}
};
cause
}

View file

@ -1,6 +1,8 @@
use rustc_hir as hir;
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
use rustc_infer::traits::{
ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation,
};
use rustc_middle::span_bug;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::{self, TypingMode};
@ -248,9 +250,22 @@ fn evaluate_host_effect_from_selection_candiate<'tcx>(
tcx.const_conditions(impl_.impl_def_id)
.instantiate(tcx, impl_.args)
.into_iter()
.map(|(trait_ref, _)| {
obligation.with(
.map(|(trait_ref, span)| {
Obligation::new(
tcx,
obligation.cause.clone().derived_host_cause(
ty::Binder::dummy(obligation.predicate),
|derived| {
ObligationCauseCode::ImplDerivedHost(Box::new(
ImplDerivedHostCause {
derived,
impl_def_id: impl_.impl_def_id,
span,
},
))
},
),
obligation.param_env,
trait_ref
.to_host_effect_clause(tcx, obligation.predicate.constness),
)