Skip to content

Commit b642740

Browse files
authored
Rollup merge of #132345 - compiler-errors:fx-diag, r=lcnr
Improve diagnostics for `HostEffectPredicate` in the new solver Adds derived cause for host effect predicates. Some diagnostics regress, but that's connected to the fact that our predicate visitor doesn't play well with aliases just yet.
2 parents 4e4a93c + ebdf19a commit b642740

File tree

14 files changed

+284
-41
lines changed

14 files changed

+284
-41
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

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ where
103103
|ecx| {
104104
// Const conditions must hold for the implied const bound to hold.
105105
ecx.add_goals(
106-
GoalSource::Misc,
106+
GoalSource::AliasBoundConstCondition,
107107
cx.const_conditions(alias_ty.def_id)
108108
.iter_instantiated(cx, alias_ty.args)
109109
.map(|trait_ref| {
@@ -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::AliasBoundConstCondition,
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
@@ -737,7 +737,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
737737
applied_do_not_recommend = true;
738738
}
739739
}
740-
if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
740+
if let Some(parent_cause) = base_cause.parent() {
741741
base_cause = parent_cause.clone();
742742
} else {
743743
break;
@@ -797,7 +797,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
797797
trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind()
798798
&& !found_kind.extends(expected_kind)
799799
{
800-
if let Some((_, Some(parent))) = obligation.cause.code().parent() {
800+
if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
801801
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
802802
trait_ref = parent.to_poly_trait_ref();
803803
} else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
@@ -945,7 +945,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
945945
let Some(typeck) = &self.typeck_results else {
946946
return false;
947947
};
948-
let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent()
948+
let Some((ObligationCauseCode::QuestionMark, Some(y))) =
949+
obligation.cause.code().parent_with_predicate()
949950
else {
950951
return false;
951952
};
@@ -1198,7 +1199,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11981199

11991200
let mut code = obligation.cause.code();
12001201
let mut pred = obligation.predicate.as_trait_clause();
1201-
while let Some((next_code, next_pred)) = code.parent() {
1202+
while let Some((next_code, next_pred)) = code.parent_with_predicate() {
12021203
if let Some(pred) = pred {
12031204
self.enter_forall(pred, |pred| {
12041205
diag.note(format!(
@@ -2114,7 +2115,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
21142115
let mut code = obligation.cause.code();
21152116
let mut trait_pred = trait_predicate;
21162117
let mut peeled = false;
2117-
while let Some((parent_code, parent_trait_pred)) = code.parent() {
2118+
while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
21182119
code = parent_code;
21192120
if let Some(parent_trait_pred) = parent_trait_pred {
21202121
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
@@ -464,7 +464,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
464464

465465
// Get the root obligation, since the leaf obligation we have may be unhelpful (#87437)
466466
let mut real_trait_pred = trait_pred;
467-
while let Some((parent_code, parent_trait_pred)) = code.parent() {
467+
while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() {
468468
code = parent_code;
469469
if let Some(parent_trait_pred) = parent_trait_pred {
470470
real_trait_pred = parent_trait_pred;
@@ -1447,7 +1447,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14471447
let mut span = obligation.cause.span;
14481448
let mut trait_pred = trait_pred;
14491449
let mut code = obligation.cause.code();
1450-
while let Some((c, Some(parent_trait_pred))) = code.parent() {
1450+
while let Some((c, Some(parent_trait_pred))) = code.parent_with_predicate() {
14511451
// We want the root obligation, in order to detect properly handle
14521452
// `for _ in &mut &mut vec![] {}`.
14531453
code = c;
@@ -3470,6 +3470,59 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
34703470
)
34713471
});
34723472
}
3473+
ObligationCauseCode::ImplDerivedHost(ref data) => {
3474+
let self_ty =
3475+
self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty());
3476+
let msg = format!(
3477+
"required for `{self_ty}` to implement `{} {}`",
3478+
data.derived.parent_host_pred.skip_binder().constness,
3479+
data.derived
3480+
.parent_host_pred
3481+
.map_bound(|pred| pred.trait_ref)
3482+
.print_only_trait_path(),
3483+
);
3484+
match tcx.hir().get_if_local(data.impl_def_id) {
3485+
Some(Node::Item(hir::Item {
3486+
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
3487+
..
3488+
})) => {
3489+
let mut spans = vec![self_ty.span];
3490+
spans.extend(of_trait.as_ref().map(|t| t.path.span));
3491+
let mut spans: MultiSpan = spans.into();
3492+
spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
3493+
err.span_note(spans, msg);
3494+
}
3495+
_ => {
3496+
err.note(msg);
3497+
}
3498+
}
3499+
ensure_sufficient_stack(|| {
3500+
self.note_obligation_cause_code(
3501+
body_id,
3502+
err,
3503+
data.derived.parent_host_pred,
3504+
param_env,
3505+
&data.derived.parent_code,
3506+
obligated_types,
3507+
seen_requirements,
3508+
long_ty_file,
3509+
)
3510+
});
3511+
}
3512+
ObligationCauseCode::BuiltinDerivedHost(ref data) => {
3513+
ensure_sufficient_stack(|| {
3514+
self.note_obligation_cause_code(
3515+
body_id,
3516+
err,
3517+
data.parent_host_pred,
3518+
param_env,
3519+
&data.parent_code,
3520+
obligated_types,
3521+
seen_requirements,
3522+
long_ty_file,
3523+
)
3524+
});
3525+
}
34733526
ObligationCauseCode::WellFormedDerived(ref data) => {
34743527
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
34753528
let parent_predicate = parent_trait_ref;

0 commit comments

Comments
 (0)