Skip to content

Commit b921c6a

Browse files
Add derived causes for host effect predicates
1 parent 33c245b commit b921c6a

File tree

14 files changed

+274
-37
lines changed

14 files changed

+274
-37
lines changed

compiler/rustc_middle/src/traits/mod.rs

+72-17
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@ impl<'tcx> ObligationCause<'tcx> {
126126
self
127127
}
128128

129+
pub fn derived_host_cause(
130+
mut self,
131+
parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
132+
variant: impl FnOnce(DerivedHostCause<'tcx>) -> ObligationCauseCode<'tcx>,
133+
) -> ObligationCause<'tcx> {
134+
self.code = variant(DerivedHostCause { parent_host_pred, parent_code: self.code }).into();
135+
self
136+
}
137+
129138
pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
130139
match self.code() {
131140
ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(),
@@ -279,6 +288,14 @@ pub enum ObligationCauseCode<'tcx> {
279288
/// Derived obligation for WF goals.
280289
WellFormedDerived(DerivedCause<'tcx>),
281290

291+
/// Derived obligation (i.e. `where` clause) on an user-provided impl
292+
/// or a trait alias.
293+
ImplDerivedHost(Box<ImplDerivedHostCause<'tcx>>),
294+
295+
/// Derived obligation (i.e. `where` clause) on an user-provided impl
296+
/// or a trait alias.
297+
BuiltinDerivedHost(DerivedHostCause<'tcx>),
298+
282299
/// Derived obligation refined to point at a specific argument in
283300
/// a call or method expression.
284301
FunctionArg {
@@ -438,36 +455,38 @@ pub enum WellFormedLoc {
438455
},
439456
}
440457

441-
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
442-
#[derive(TypeVisitable, TypeFoldable)]
443-
pub struct ImplDerivedCause<'tcx> {
444-
pub derived: DerivedCause<'tcx>,
445-
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
446-
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
447-
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
448-
/// that exceptional case where appropriate.
449-
pub impl_or_alias_def_id: DefId,
450-
/// The index of the derived predicate in the parent impl's predicates.
451-
pub impl_def_predicate_index: Option<usize>,
452-
pub span: Span,
453-
}
454-
455458
impl<'tcx> ObligationCauseCode<'tcx> {
456459
/// Returns the base obligation, ignoring derived obligations.
457460
pub fn peel_derives(&self) -> &Self {
458461
let mut base_cause = self;
459-
while let Some((parent_code, _)) = base_cause.parent() {
462+
while let Some(parent_code) = base_cause.parent() {
460463
base_cause = parent_code;
461464
}
462465
base_cause
463466
}
464467

468+
pub fn parent(&self) -> Option<&Self> {
469+
match self {
470+
ObligationCauseCode::FunctionArg { parent_code, .. } => Some(parent_code),
471+
ObligationCauseCode::BuiltinDerived(derived)
472+
| ObligationCauseCode::WellFormedDerived(derived)
473+
| ObligationCauseCode::ImplDerived(box ImplDerivedCause { derived, .. }) => {
474+
Some(&derived.parent_code)
475+
}
476+
ObligationCauseCode::BuiltinDerivedHost(derived)
477+
| ObligationCauseCode::ImplDerivedHost(box ImplDerivedHostCause { derived, .. }) => {
478+
Some(&derived.parent_code)
479+
}
480+
_ => None,
481+
}
482+
}
483+
465484
/// Returns the base obligation and the base trait predicate, if any, ignoring
466485
/// derived obligations.
467486
pub fn peel_derives_with_predicate(&self) -> (&Self, Option<ty::PolyTraitPredicate<'tcx>>) {
468487
let mut base_cause = self;
469488
let mut base_trait_pred = None;
470-
while let Some((parent_code, parent_pred)) = base_cause.parent() {
489+
while let Some((parent_code, parent_pred)) = base_cause.parent_with_predicate() {
471490
base_cause = parent_code;
472491
if let Some(parent_pred) = parent_pred {
473492
base_trait_pred = Some(parent_pred);
@@ -477,7 +496,7 @@ impl<'tcx> ObligationCauseCode<'tcx> {
477496
(base_cause, base_trait_pred)
478497
}
479498

480-
pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
499+
pub fn parent_with_predicate(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
481500
match self {
482501
ObligationCauseCode::FunctionArg { parent_code, .. } => Some((parent_code, None)),
483502
ObligationCauseCode::BuiltinDerived(derived)
@@ -555,6 +574,42 @@ pub struct DerivedCause<'tcx> {
555574
pub parent_code: InternedObligationCauseCode<'tcx>,
556575
}
557576

577+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
578+
#[derive(TypeVisitable, TypeFoldable)]
579+
pub struct ImplDerivedCause<'tcx> {
580+
pub derived: DerivedCause<'tcx>,
581+
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
582+
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
583+
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
584+
/// that exceptional case where appropriate.
585+
pub impl_or_alias_def_id: DefId,
586+
/// The index of the derived predicate in the parent impl's predicates.
587+
pub impl_def_predicate_index: Option<usize>,
588+
pub span: Span,
589+
}
590+
591+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
592+
#[derive(TypeVisitable, TypeFoldable)]
593+
pub struct DerivedHostCause<'tcx> {
594+
/// The trait predicate of the parent obligation that led to the
595+
/// current obligation. Note that only trait obligations lead to
596+
/// derived obligations, so we just store the trait predicate here
597+
/// directly.
598+
pub parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
599+
600+
/// The parent trait had this cause.
601+
pub parent_code: InternedObligationCauseCode<'tcx>,
602+
}
603+
604+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
605+
#[derive(TypeVisitable, TypeFoldable)]
606+
pub struct ImplDerivedHostCause<'tcx> {
607+
pub derived: DerivedHostCause<'tcx>,
608+
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
609+
pub impl_def_id: DefId,
610+
pub span: Span,
611+
}
612+
558613
#[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)]
559614
pub enum SelectionError<'tcx> {
560615
/// The trait is not implemented.

compiler/rustc_middle/src/ty/predicate.rs

+22
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,28 @@ impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyProjectionPredicate<'tcx>> for Clause<'t
634634
}
635635
}
636636

637+
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>>
638+
for Predicate<'tcx>
639+
{
640+
fn upcast_from(
641+
from: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
642+
tcx: TyCtxt<'tcx>,
643+
) -> Self {
644+
from.map_bound(ty::ClauseKind::HostEffect).upcast(tcx)
645+
}
646+
}
647+
648+
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>>
649+
for Clause<'tcx>
650+
{
651+
fn upcast_from(
652+
from: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
653+
tcx: TyCtxt<'tcx>,
654+
) -> Self {
655+
from.map_bound(ty::ClauseKind::HostEffect).upcast(tcx)
656+
}
657+
}
658+
637659
impl<'tcx> UpcastFrom<TyCtxt<'tcx>, NormalizesTo<'tcx>> for Predicate<'tcx> {
638660
fn upcast_from(from: NormalizesTo<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
639661
PredicateKind::NormalizesTo(from).upcast(tcx)

compiler/rustc_next_trait_solver/src/solve/effect_goals.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ where
352352

353353
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
354354
ecx.add_goals(
355-
GoalSource::Misc,
355+
GoalSource::ImplWhereBound,
356356
const_conditions.into_iter().map(|trait_ref| {
357357
goal.with(
358358
cx,

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
754754
applied_do_not_recommend = true;
755755
}
756756
}
757-
if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
757+
if let Some(parent_cause) = base_cause.parent() {
758758
base_cause = parent_cause.clone();
759759
} else {
760760
break;
@@ -779,7 +779,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
779779
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
780780
&& !found_kind.extends(expected_kind)
781781
{
782-
if let Some((_, Some(parent))) = obligation.cause.code().parent() {
782+
if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
783783
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
784784
trait_ref = parent.to_poly_trait_ref();
785785
} else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
@@ -925,7 +925,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
925925
let Some(typeck) = &self.typeck_results else {
926926
return false;
927927
};
928-
let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent()
928+
let Some((ObligationCauseCode::QuestionMark, Some(y))) =
929+
obligation.cause.code().parent_with_predicate()
929930
else {
930931
return false;
931932
};
@@ -1178,7 +1179,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11781179

11791180
let mut code = obligation.cause.code();
11801181
let mut pred = obligation.predicate.as_trait_clause();
1181-
while let Some((next_code, next_pred)) = code.parent() {
1182+
while let Some((next_code, next_pred)) = code.parent_with_predicate() {
11821183
if let Some(pred) = pred {
11831184
self.enter_forall(pred, |pred| {
11841185
diag.note(format!(
@@ -2093,7 +2094,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
20932094
let mut code = obligation.cause.code();
20942095
let mut trait_pred = trait_predicate;
20952096
let mut peeled = false;
2096-
while let Some((parent_code, parent_trait_pred)) = code.parent() {
2097+
while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
20972098
code = parent_code;
20982099
if let Some(parent_trait_pred) = parent_trait_pred {
20992100
trait_pred = parent_trait_pred;

compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs

+55-2
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
460460
{
461461
// Suggest dereferencing the argument to a function/method call if possible
462462
let mut real_trait_pred = trait_pred;
463-
while let Some((parent_code, parent_trait_pred)) = code.parent() {
463+
while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
464464
code = parent_code;
465465
if let Some(parent_trait_pred) = parent_trait_pred {
466466
real_trait_pred = parent_trait_pred;
@@ -1476,7 +1476,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14761476
let mut span = obligation.cause.span;
14771477
let mut trait_pred = trait_pred;
14781478
let mut code = obligation.cause.code();
1479-
while let Some((c, Some(parent_trait_pred))) = code.parent() {
1479+
while let Some((c, Some(parent_trait_pred))) = code.parent_with_predicate() {
14801480
// We want the root obligation, in order to detect properly handle
14811481
// `for _ in &mut &mut vec![] {}`.
14821482
code = c;
@@ -3501,6 +3501,59 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
35013501
)
35023502
});
35033503
}
3504+
ObligationCauseCode::ImplDerivedHost(ref data) => {
3505+
let self_ty =
3506+
self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty());
3507+
let msg = format!(
3508+
"required for `{self_ty}` to implement `{} {}`",
3509+
data.derived.parent_host_pred.skip_binder().constness,
3510+
data.derived
3511+
.parent_host_pred
3512+
.map_bound(|pred| pred.trait_ref)
3513+
.print_only_trait_path(),
3514+
);
3515+
match tcx.hir().get_if_local(data.impl_def_id) {
3516+
Some(Node::Item(hir::Item {
3517+
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
3518+
..
3519+
})) => {
3520+
let mut spans = vec![self_ty.span];
3521+
spans.extend(of_trait.as_ref().map(|t| t.path.span));
3522+
let mut spans: MultiSpan = spans.into();
3523+
spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
3524+
err.span_note(spans, msg);
3525+
}
3526+
_ => {
3527+
err.note(msg);
3528+
}
3529+
}
3530+
ensure_sufficient_stack(|| {
3531+
self.note_obligation_cause_code(
3532+
body_id,
3533+
err,
3534+
data.derived.parent_host_pred,
3535+
param_env,
3536+
&data.derived.parent_code,
3537+
obligated_types,
3538+
seen_requirements,
3539+
long_ty_file,
3540+
)
3541+
});
3542+
}
3543+
ObligationCauseCode::BuiltinDerivedHost(ref data) => {
3544+
ensure_sufficient_stack(|| {
3545+
self.note_obligation_cause_code(
3546+
body_id,
3547+
err,
3548+
data.parent_host_pred,
3549+
param_env,
3550+
&data.parent_code,
3551+
obligated_types,
3552+
seen_requirements,
3553+
long_ty_file,
3554+
)
3555+
});
3556+
}
35043557
ObligationCauseCode::WellFormedDerived(ref data) => {
35053558
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
35063559
let parent_predicate = parent_trait_ref;

0 commit comments

Comments
 (0)