Add derived causes for host effect predicates
This commit is contained in:
parent
243d2ca4db
commit
2be9ffc1af
15 changed files with 278 additions and 39 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue