Skip to content

Commit bb76b62

Browse files
Derived causes for ~const bounds
1 parent c96ba49 commit bb76b62

File tree

8 files changed

+229
-21
lines changed

8 files changed

+229
-21
lines changed

compiler/rustc_middle/src/traits/mod.rs

+53-14
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(),
@@ -270,6 +279,14 @@ pub enum ObligationCauseCode<'tcx> {
270279
/// Derived obligation for WF goals.
271280
WellFormedDerived(DerivedCause<'tcx>),
272281

282+
/// Derived obligation (i.e. `where` clause) on an user-provided impl
283+
/// or a trait alias.
284+
ImplDerivedHost(Box<ImplDerivedHostCause<'tcx>>),
285+
286+
/// Derived obligation (i.e. `where` clause) on an user-provided impl
287+
/// or a trait alias.
288+
BuiltinDerivedHost(DerivedHostCause<'tcx>),
289+
273290
/// Derived obligation refined to point at a specific argument in
274291
/// a call or method expression.
275292
FunctionArg {
@@ -429,20 +446,6 @@ pub enum WellFormedLoc {
429446
},
430447
}
431448

432-
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
433-
#[derive(TypeVisitable, TypeFoldable)]
434-
pub struct ImplDerivedCause<'tcx> {
435-
pub derived: DerivedCause<'tcx>,
436-
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
437-
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
438-
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
439-
/// that exceptional case where appropriate.
440-
pub impl_or_alias_def_id: DefId,
441-
/// The index of the derived predicate in the parent impl's predicates.
442-
pub impl_def_predicate_index: Option<usize>,
443-
pub span: Span,
444-
}
445-
446449
impl<'tcx> ObligationCauseCode<'tcx> {
447450
/// Returns the base obligation, ignoring derived obligations.
448451
pub fn peel_derives(&self) -> &Self {
@@ -546,6 +549,42 @@ pub struct DerivedCause<'tcx> {
546549
pub parent_code: InternedObligationCauseCode<'tcx>,
547550
}
548551

552+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
553+
#[derive(TypeVisitable, TypeFoldable)]
554+
pub struct ImplDerivedCause<'tcx> {
555+
pub derived: DerivedCause<'tcx>,
556+
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
557+
/// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
558+
/// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
559+
/// that exceptional case where appropriate.
560+
pub impl_or_alias_def_id: DefId,
561+
/// The index of the derived predicate in the parent impl's predicates.
562+
pub impl_def_predicate_index: Option<usize>,
563+
pub span: Span,
564+
}
565+
566+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
567+
#[derive(TypeVisitable, TypeFoldable)]
568+
pub struct DerivedHostCause<'tcx> {
569+
/// The trait predicate of the parent obligation that led to the
570+
/// current obligation. Note that only trait obligations lead to
571+
/// derived obligations, so we just store the trait predicate here
572+
/// directly.
573+
pub parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
574+
575+
/// The parent trait had this cause.
576+
pub parent_code: InternedObligationCauseCode<'tcx>,
577+
}
578+
579+
#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
580+
#[derive(TypeVisitable, TypeFoldable)]
581+
pub struct ImplDerivedHostCause<'tcx> {
582+
pub derived: DerivedHostCause<'tcx>,
583+
/// The `DefId` of the `impl` that gave rise to the `derived` obligation.
584+
pub impl_def_id: DefId,
585+
pub span: Span,
586+
}
587+
549588
#[derive(Clone, Debug, TypeVisitable)]
550589
pub enum SelectionError<'tcx> {
551590
/// 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_trait_selection/src/error_reporting/traits/suggestions.rs

+53
Original file line numberDiff line numberDiff line change
@@ -3465,6 +3465,59 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
34653465
)
34663466
});
34673467
}
3468+
ObligationCauseCode::ImplDerivedHost(ref data) => {
3469+
let self_ty =
3470+
self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty());
3471+
let msg = format!(
3472+
"required for `{self_ty}` to implement `{} {}`",
3473+
data.derived.parent_host_pred.skip_binder().constness,
3474+
data.derived
3475+
.parent_host_pred
3476+
.map_bound(|pred| pred.trait_ref)
3477+
.print_only_trait_path(),
3478+
);
3479+
match tcx.hir().get_if_local(data.impl_def_id) {
3480+
Some(Node::Item(hir::Item {
3481+
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
3482+
..
3483+
})) => {
3484+
let mut spans = vec![self_ty.span];
3485+
spans.extend(of_trait.as_ref().map(|t| t.path.span));
3486+
let mut spans: MultiSpan = spans.into();
3487+
spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
3488+
err.span_note(spans, msg);
3489+
}
3490+
_ => {
3491+
err.note(msg);
3492+
}
3493+
}
3494+
ensure_sufficient_stack(|| {
3495+
self.note_obligation_cause_code(
3496+
body_id,
3497+
err,
3498+
data.derived.parent_host_pred,
3499+
param_env,
3500+
&data.derived.parent_code,
3501+
obligated_types,
3502+
seen_requirements,
3503+
long_ty_file,
3504+
)
3505+
});
3506+
}
3507+
ObligationCauseCode::BuiltinDerivedHost(ref data) => {
3508+
ensure_sufficient_stack(|| {
3509+
self.note_obligation_cause_code(
3510+
body_id,
3511+
err,
3512+
data.parent_host_pred,
3513+
param_env,
3514+
&data.parent_code,
3515+
obligated_types,
3516+
seen_requirements,
3517+
long_ty_file,
3518+
)
3519+
});
3520+
}
34683521
ObligationCauseCode::WellFormedDerived(ref data) => {
34693522
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
34703523
let parent_predicate = parent_trait_ref;

compiler/rustc_trait_selection/src/solve/fulfill.rs

+59-4
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
482482
};
483483

484484
let mut impl_where_bound_count = 0;
485+
let mut impl_const_condition_bound_count = 0;
485486
for nested_goal in candidate.instantiate_nested_goals(self.span()) {
486487
trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result()));
487488

@@ -507,9 +508,15 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
507508
));
508509
impl_where_bound_count += 1;
509510
}
510-
(ChildMode::Host(_), GoalSource::ImplWhereBound) => {
511-
// TODO:
512-
obligation = make_obligation(self.obligation.cause.clone());
511+
(ChildMode::Host(parent_host_pred), GoalSource::ImplWhereBound) => {
512+
obligation = make_obligation(derive_host_cause(
513+
tcx,
514+
candidate.kind(),
515+
self.obligation.cause.clone(),
516+
impl_const_condition_bound_count,
517+
parent_host_pred,
518+
));
519+
impl_const_condition_bound_count += 1;
513520
}
514521
// Skip over a higher-ranked predicate.
515522
(_, GoalSource::InstantiateHigherRanked) => {
@@ -572,7 +579,6 @@ enum ChildMode<'tcx> {
572579
// Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
573580
// and skip all `GoalSource::Misc`, which represent useless obligations
574581
// such as alias-eq which may not hold.
575-
#[expect(dead_code)]
576582
Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>),
577583
// Skip trying to derive an `ObligationCause` from this obligation, and
578584
// report *all* sub-obligations as if they came directly from the parent
@@ -615,3 +621,52 @@ fn derive_cause<'tcx>(
615621
};
616622
cause
617623
}
624+
625+
fn derive_host_cause<'tcx>(
626+
tcx: TyCtxt<'tcx>,
627+
candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
628+
mut cause: ObligationCause<'tcx>,
629+
idx: usize,
630+
parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
631+
) -> ObligationCause<'tcx> {
632+
match candidate_kind {
633+
inspect::ProbeKind::TraitCandidate {
634+
source: CandidateSource::Impl(impl_def_id),
635+
result: _,
636+
} => {
637+
if let Some((_, span)) = tcx
638+
.predicates_of(impl_def_id)
639+
.instantiate_identity(tcx)
640+
.into_iter()
641+
.chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map(
642+
|(trait_ref, span)| {
643+
(
644+
trait_ref.to_host_effect_clause(
645+
tcx,
646+
parent_host_pred.skip_binder().constness,
647+
),
648+
span,
649+
)
650+
},
651+
))
652+
.nth(idx)
653+
{
654+
cause =
655+
cause.derived_host_cause(parent_host_pred, |derived| {
656+
ObligationCauseCode::ImplDerivedHost(Box::new(
657+
traits::ImplDerivedHostCause { derived, impl_def_id, span },
658+
))
659+
})
660+
}
661+
}
662+
inspect::ProbeKind::TraitCandidate {
663+
source: CandidateSource::BuiltinImpl(..),
664+
result: _,
665+
} => {
666+
cause =
667+
cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost);
668+
}
669+
_ => {}
670+
};
671+
cause
672+
}

compiler/rustc_trait_selection/src/traits/effects.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use rustc_hir as hir;
22
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
3-
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
3+
use rustc_infer::traits::{
4+
ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation,
5+
};
46
use rustc_middle::span_bug;
57
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
68
use rustc_middle::ty::{self, TypingMode};
@@ -132,9 +134,22 @@ fn evaluate_host_effect_from_selection_candiate<'tcx>(
132134
tcx.const_conditions(impl_.impl_def_id)
133135
.instantiate(tcx, impl_.args)
134136
.into_iter()
135-
.map(|(trait_ref, _)| {
136-
obligation.with(
137+
.map(|(trait_ref, span)| {
138+
Obligation::new(
137139
tcx,
140+
obligation.cause.clone().derived_host_cause(
141+
ty::Binder::dummy(obligation.predicate),
142+
|derived| {
143+
ObligationCauseCode::ImplDerivedHost(Box::new(
144+
ImplDerivedHostCause {
145+
derived,
146+
impl_def_id: impl_.impl_def_id,
147+
span,
148+
},
149+
))
150+
},
151+
),
152+
obligation.param_env,
138153
trait_ref
139154
.to_host_effect_clause(tcx, obligation.predicate.constness),
140155
)

compiler/rustc_type_ir/src/binder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ impl_binder_encode_decode! {
9191
ty::ExistentialPredicate<I>,
9292
ty::TraitRef<I>,
9393
ty::ExistentialTraitRef<I>,
94+
ty::HostEffectPredicate<I>,
9495
}
9596

9697
impl<I: Interner, T> Binder<I, T>

tests/ui/const-generics/issues/issue-88119.stderr

+18
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,30 @@ error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{con
1111
|
1212
LL | impl<T: ?Sized + ConstName> const ConstName for &T
1313
| ^^ cannot normalize `<&T as ConstName>::{constant#0}`
14+
|
15+
note: required for `&T` to implement `~const ConstName`
16+
--> $DIR/issue-88119.rs:19:35
17+
|
18+
LL | impl<T: ?Sized + ConstName> const ConstName for &T
19+
| ^^^^^^^^^ ^^
20+
LL | where
21+
LL | [(); name_len::<T>()]:,
22+
| --------------------- unsatisfied trait bound introduced here
1423

1524
error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}`
1625
--> $DIR/issue-88119.rs:26:49
1726
|
1827
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
1928
| ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}`
29+
|
30+
note: required for `&mut T` to implement `~const ConstName`
31+
--> $DIR/issue-88119.rs:26:35
32+
|
33+
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
34+
| ^^^^^^^^^ ^^^^^^
35+
LL | where
36+
LL | [(); name_len::<T>()]:,
37+
| --------------------- unsatisfied trait bound introduced here
2038

2139
error: aborting due to 3 previous errors
2240

tests/ui/traits/const-traits/item-bound-entailment-fails.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ error[E0277]: the trait bound `T: ~const Bar` is not satisfied
2525
LL | type Assoc<T> = C<T>
2626
| ^^^^
2727
|
28+
note: required for `C<T>` to implement `~const Bar`
29+
--> $DIR/item-bound-entailment-fails.rs:15:15
30+
|
31+
LL | impl<T> const Bar for C<T> where T: ~const Bar {}
32+
| ^^^ ^^^^ ------ unsatisfied trait bound introduced here
2833
note: required by a bound in `Foo::Assoc`
2934
--> $DIR/item-bound-entailment-fails.rs:6:20
3035
|

0 commit comments

Comments
 (0)