Skip to content

Commit c439226

Browse files
Add derived causes for host effect predicates
1 parent addbd00 commit c439226

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
@@ -125,6 +125,15 @@ impl<'tcx> ObligationCause<'tcx> {
125125
self
126126
}
127127

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

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

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

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

479-
pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
498+
pub fn parent_with_predicate(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
480499
match self {
481500
ObligationCauseCode::FunctionArg { parent_code, .. } => Some((parent_code, None)),
482501
ObligationCauseCode::BuiltinDerived(derived)
@@ -573,6 +592,42 @@ pub struct DerivedCause<'tcx> {
573592
pub parent_code: InternedObligationCauseCode<'tcx>,
574593
}
575594

595+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
596+
#[derive(TypeVisitable, TypeFoldable)]
597+
pub struct ImplDerivedCause<'tcx> {
598+
pub derived: DerivedCause<'tcx>,
599+
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
600+
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
601+
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
602+
/// that exceptional case where appropriate.
603+
pub impl_or_alias_def_id: DefId,
604+
/// The index of the derived predicate in the parent impl's predicates.
605+
pub impl_def_predicate_index: Option<usize>,
606+
pub span: Span,
607+
}
608+
609+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
610+
#[derive(TypeVisitable, TypeFoldable)]
611+
pub struct DerivedHostCause<'tcx> {
612+
/// The trait predicate of the parent obligation that led to the
613+
/// current obligation. Note that only trait obligations lead to
614+
/// derived obligations, so we just store the trait predicate here
615+
/// directly.
616+
pub parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
617+
618+
/// The parent trait had this cause.
619+
pub parent_code: InternedObligationCauseCode<'tcx>,
620+
}
621+
622+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
623+
#[derive(TypeVisitable, TypeFoldable)]
624+
pub struct ImplDerivedHostCause<'tcx> {
625+
pub derived: DerivedHostCause<'tcx>,
626+
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
627+
pub impl_def_id: DefId,
628+
pub span: Span,
629+
}
630+
576631
#[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)]
577632
pub enum SelectionError<'tcx> {
578633
/// 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
@@ -353,7 +353,7 @@ where
353353

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

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
753753
applied_do_not_recommend = true;
754754
}
755755
}
756-
if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
756+
if let Some(parent_cause) = base_cause.parent() {
757757
base_cause = parent_cause.clone();
758758
} else {
759759
break;
@@ -778,7 +778,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
778778
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
779779
&& !found_kind.extends(expected_kind)
780780
{
781-
if let Some((_, Some(parent))) = obligation.cause.code().parent() {
781+
if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
782782
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
783783
trait_ref = parent.to_poly_trait_ref();
784784
} else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
@@ -924,7 +924,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
924924
let Some(typeck) = &self.typeck_results else {
925925
return false;
926926
};
927-
let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent()
927+
let Some((ObligationCauseCode::QuestionMark, Some(y))) =
928+
obligation.cause.code().parent_with_predicate()
928929
else {
929930
return false;
930931
};
@@ -1177,7 +1178,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11771178

11781179
let mut code = obligation.cause.code();
11791180
let mut pred = obligation.predicate.as_trait_clause();
1180-
while let Some((next_code, next_pred)) = code.parent() {
1181+
while let Some((next_code, next_pred)) = code.parent_with_predicate() {
11811182
if let Some(pred) = pred {
11821183
self.enter_forall(pred, |pred| {
11831184
diag.note(format!(
@@ -2092,7 +2093,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
20922093
let mut code = obligation.cause.code();
20932094
let mut trait_pred = trait_predicate;
20942095
let mut peeled = false;
2095-
while let Some((parent_code, parent_trait_pred)) = code.parent() {
2096+
while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
20962097
code = parent_code;
20972098
if let Some(parent_trait_pred) = parent_trait_pred {
20982099
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
@@ -462,7 +462,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
462462
{
463463
// Suggest dereferencing the argument to a function/method call if possible
464464
let mut real_trait_pred = trait_pred;
465-
while let Some((parent_code, parent_trait_pred)) = code.parent() {
465+
while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
466466
code = parent_code;
467467
if let Some(parent_trait_pred) = parent_trait_pred {
468468
real_trait_pred = parent_trait_pred;
@@ -1472,7 +1472,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14721472
let mut span = obligation.cause.span;
14731473
let mut trait_pred = trait_pred;
14741474
let mut code = obligation.cause.code();
1475-
while let Some((c, Some(parent_trait_pred))) = code.parent() {
1475+
while let Some((c, Some(parent_trait_pred))) = code.parent_with_predicate() {
14761476
// We want the root obligation, in order to detect properly handle
14771477
// `for _ in &mut &mut vec![] {}`.
14781478
code = c;
@@ -3497,6 +3497,59 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
34973497
)
34983498
});
34993499
}
3500+
ObligationCauseCode::ImplDerivedHost(ref data) => {
3501+
let self_ty =
3502+
self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty());
3503+
let msg = format!(
3504+
"required for `{self_ty}` to implement `{} {}`",
3505+
data.derived.parent_host_pred.skip_binder().constness,
3506+
data.derived
3507+
.parent_host_pred
3508+
.map_bound(|pred| pred.trait_ref)
3509+
.print_only_trait_path(),
3510+
);
3511+
match tcx.hir().get_if_local(data.impl_def_id) {
3512+
Some(Node::Item(hir::Item {
3513+
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
3514+
..
3515+
})) => {
3516+
let mut spans = vec![self_ty.span];
3517+
spans.extend(of_trait.as_ref().map(|t| t.path.span));
3518+
let mut spans: MultiSpan = spans.into();
3519+
spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
3520+
err.span_note(spans, msg);
3521+
}
3522+
_ => {
3523+
err.note(msg);
3524+
}
3525+
}
3526+
ensure_sufficient_stack(|| {
3527+
self.note_obligation_cause_code(
3528+
body_id,
3529+
err,
3530+
data.derived.parent_host_pred,
3531+
param_env,
3532+
&data.derived.parent_code,
3533+
obligated_types,
3534+
seen_requirements,
3535+
long_ty_file,
3536+
)
3537+
});
3538+
}
3539+
ObligationCauseCode::BuiltinDerivedHost(ref data) => {
3540+
ensure_sufficient_stack(|| {
3541+
self.note_obligation_cause_code(
3542+
body_id,
3543+
err,
3544+
data.parent_host_pred,
3545+
param_env,
3546+
&data.parent_code,
3547+
obligated_types,
3548+
seen_requirements,
3549+
long_ty_file,
3550+
)
3551+
});
3552+
}
35003553
ObligationCauseCode::WellFormedDerived(ref data) => {
35013554
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
35023555
let parent_predicate = parent_trait_ref;

0 commit comments

Comments
 (0)