Skip to content

Commit 049c327

Browse files
committed
On E0277, point at type that doesn't implement bound
When encountering an unmet trait bound, point at local type that doesn't implement the trait: ``` error[E0277]: the trait bound `Bar<T>: Foo` is not satisfied --> $DIR/issue-64855.rs:9:19 | LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ; | ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | help: the trait `Foo` is not implemented for `Bar<T>` --> $DIR/issue-64855.rs:9:1 | LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ; | ^^^^^^^^^^^^^^^^^ ```
1 parent f5703d5 commit 049c327

File tree

121 files changed

+1094
-249
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+1094
-249
lines changed

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

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
275275
*err.long_ty_path() = long_ty_file;
276276

277277
let mut suggested = false;
278+
let mut noted_missing_impl = false;
278279
if is_try_conversion || is_question_mark {
279-
suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
280+
(suggested, noted_missing_impl) = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
280281
}
281282

282283
if let Some(ret_span) = self.return_type_span(&obligation) {
@@ -335,6 +336,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
335336
return err.emit();
336337
}
337338

339+
let ty_span = match leaf_trait_predicate.self_ty().skip_binder().kind() {
340+
ty::Adt(def, _) if def.did().is_local()
341+
&& !self.can_suggest_derive(&obligation, leaf_trait_predicate) => self.tcx.def_span(def.did()),
342+
_ => DUMMY_SP,
343+
};
338344
if let Some(s) = label {
339345
// If it has a custom `#[rustc_on_unimplemented]`
340346
// error message, let's display it as the label!
@@ -347,15 +353,28 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
347353
// Don't say "the trait `FromResidual<Option<Infallible>>` is
348354
// not implemented for `Result<T, E>`".
349355
{
350-
err.help(explanation);
356+
// We do this just so that the JSON output's `help` position is the
357+
// right one and not `file.rs:1:1`. The render is the same.
358+
if ty_span == DUMMY_SP {
359+
err.help(explanation);
360+
} else {
361+
err.span_help(ty_span, explanation);
362+
}
351363
}
352364
} else if let Some(custom_explanation) = safe_transmute_explanation {
353365
err.span_label(span, custom_explanation);
354-
} else if explanation.len() > self.tcx.sess.diagnostic_width() {
366+
} else if (explanation.len() > self.tcx.sess.diagnostic_width() || ty_span != DUMMY_SP) && !noted_missing_impl {
355367
// Really long types don't look good as span labels, instead move it
356368
// to a `help`.
357369
err.span_label(span, "unsatisfied trait bound");
358-
err.help(explanation);
370+
371+
// We do this just so that the JSON output's `help` position is the
372+
// right one and not `file.rs:1:1`. The render is the same.
373+
if ty_span == DUMMY_SP {
374+
err.help(explanation);
375+
} else {
376+
err.span_help(ty_span, explanation);
377+
}
359378
} else {
360379
err.span_label(span, explanation);
361380
}
@@ -939,7 +958,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
939958
obligation: &PredicateObligation<'tcx>,
940959
trait_pred: ty::PolyTraitPredicate<'tcx>,
941960
err: &mut Diag<'_>,
942-
) -> bool {
961+
) -> (bool, bool) {
943962
let span = obligation.cause.span;
944963
/// Look for the (direct) sub-expr of `?`, and return it if it's a `.` method call.
945964
struct FindMethodSubexprOfTry {
@@ -959,21 +978,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
959978
}
960979
}
961980
let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
962-
let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false };
981+
let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return (false, false) };
963982
let ControlFlow::Break(expr) =
964983
(FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir_body(body_id))
965984
else {
966-
return false;
985+
return (false, false);
967986
};
968987
let Some(typeck) = &self.typeck_results else {
969-
return false;
988+
return (false, false);
970989
};
971990
let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else {
972-
return false;
991+
return (false, false);
973992
};
974993
let self_ty = trait_pred.skip_binder().self_ty();
975994
let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
976-
self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);
995+
let noted_missing_impl =
996+
self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);
977997

978998
let mut prev_ty = self.resolve_vars_if_possible(
979999
typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
@@ -1137,7 +1157,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11371157
}
11381158
prev = Some(err_ty);
11391159
}
1140-
suggested
1160+
(suggested, noted_missing_impl)
11411161
}
11421162

11431163
fn note_missing_impl_for_question_mark(
@@ -1146,7 +1166,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11461166
self_ty: Ty<'_>,
11471167
found_ty: Option<Ty<'_>>,
11481168
trait_pred: ty::PolyTraitPredicate<'tcx>,
1149-
) {
1169+
) -> bool {
11501170
match (self_ty.kind(), found_ty) {
11511171
(ty::Adt(def, _), Some(ty))
11521172
if let ty::Adt(found, _) = ty.kind()
@@ -1187,8 +1207,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11871207
format!("`{ty}` needs to implement `Into<{self_ty}>`"),
11881208
);
11891209
}
1190-
_ => {}
1210+
_ => return false,
11911211
}
1212+
true
11921213
}
11931214

11941215
fn report_const_param_not_wf(

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

Lines changed: 54 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3853,59 +3853,71 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
38533853
}
38543854
}
38553855

3856-
pub fn suggest_derive(
3856+
pub fn can_suggest_derive(
38573857
&self,
38583858
obligation: &PredicateObligation<'tcx>,
3859-
err: &mut Diag<'_>,
38603859
trait_pred: ty::PolyTraitPredicate<'tcx>,
3861-
) {
3860+
) -> bool {
38623861
if trait_pred.polarity() == ty::PredicatePolarity::Negative {
3863-
return;
3862+
return false;
38643863
}
38653864
let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
3866-
return;
3865+
return false;
38673866
};
38683867
let (adt, args) = match trait_pred.skip_binder().self_ty().kind() {
38693868
ty::Adt(adt, args) if adt.did().is_local() => (adt, args),
3870-
_ => return,
3869+
_ => return false,
38713870
};
3872-
let can_derive = {
3873-
let is_derivable_trait = match diagnostic_name {
3874-
sym::Default => !adt.is_enum(),
3875-
sym::PartialEq | sym::PartialOrd => {
3876-
let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
3877-
trait_pred.skip_binder().self_ty() == rhs_ty
3878-
}
3879-
sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true,
3880-
_ => false,
3881-
};
3882-
is_derivable_trait &&
3883-
// Ensure all fields impl the trait.
3884-
adt.all_fields().all(|field| {
3885-
let field_ty = ty::GenericArg::from(field.ty(self.tcx, args));
3886-
let trait_args = match diagnostic_name {
3887-
sym::PartialEq | sym::PartialOrd => {
3888-
Some(field_ty)
3889-
}
3890-
_ => None,
3891-
};
3892-
let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
3893-
trait_ref: ty::TraitRef::new(self.tcx,
3894-
trait_pred.def_id(),
3895-
[field_ty].into_iter().chain(trait_args),
3896-
),
3897-
..*tr
3898-
});
3899-
let field_obl = Obligation::new(
3900-
self.tcx,
3901-
obligation.cause.clone(),
3902-
obligation.param_env,
3903-
trait_pred,
3904-
);
3905-
self.predicate_must_hold_modulo_regions(&field_obl)
3906-
})
3871+
let is_derivable_trait = match diagnostic_name {
3872+
sym::Default => !adt.is_enum(),
3873+
sym::PartialEq | sym::PartialOrd => {
3874+
let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1);
3875+
trait_pred.skip_binder().self_ty() == rhs_ty
3876+
}
3877+
sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true,
3878+
_ => false,
3879+
};
3880+
is_derivable_trait &&
3881+
// Ensure all fields impl the trait.
3882+
adt.all_fields().all(|field| {
3883+
let field_ty = ty::GenericArg::from(field.ty(self.tcx, args));
3884+
let trait_args = match diagnostic_name {
3885+
sym::PartialEq | sym::PartialOrd => {
3886+
Some(field_ty)
3887+
}
3888+
_ => None,
3889+
};
3890+
let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
3891+
trait_ref: ty::TraitRef::new(self.tcx,
3892+
trait_pred.def_id(),
3893+
[field_ty].into_iter().chain(trait_args),
3894+
),
3895+
..*tr
3896+
});
3897+
let field_obl = Obligation::new(
3898+
self.tcx,
3899+
obligation.cause.clone(),
3900+
obligation.param_env,
3901+
trait_pred,
3902+
);
3903+
self.predicate_must_hold_modulo_regions(&field_obl)
3904+
})
3905+
}
3906+
3907+
pub fn suggest_derive(
3908+
&self,
3909+
obligation: &PredicateObligation<'tcx>,
3910+
err: &mut Diag<'_>,
3911+
trait_pred: ty::PolyTraitPredicate<'tcx>,
3912+
) {
3913+
let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else {
3914+
return;
3915+
};
3916+
let adt = match trait_pred.skip_binder().self_ty().kind() {
3917+
ty::Adt(adt, _) if adt.did().is_local() => adt,
3918+
_ => return,
39073919
};
3908-
if can_derive {
3920+
if self.can_suggest_derive(obligation, trait_pred) {
39093921
err.span_suggestion_verbose(
39103922
self.tcx.def_span(adt.did()).shrink_to_lo(),
39113923
format!(

tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisf
22
--> $DIR/rustc-dev-remap.rs:LL:COL
33
|
44
LL | type Result = NotAValidResultType;
5-
| ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType`
5+
| ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
66
|
7+
help: the trait `VisitorResult` is not implemented for `NotAValidResultType`
8+
--> $DIR/rustc-dev-remap.rs:LL:COL
9+
|
10+
LL | struct NotAValidResultType;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
712
= help: the following other types implement trait `VisitorResult`:
813
()
914
ControlFlow<T>

tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisf
22
--> $DIR/rustc-dev-remap.rs:LL:COL
33
|
44
LL | type Result = NotAValidResultType;
5-
| ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType`
5+
| ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
66
|
7+
help: the trait `VisitorResult` is not implemented for `NotAValidResultType`
8+
--> $DIR/rustc-dev-remap.rs:LL:COL
9+
|
10+
LL | struct NotAValidResultType;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
712
= help: the following other types implement trait `VisitorResult`:
813
()
914
ControlFlow<T>

tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ LL | #[derive(Diagnostic)]
55
| ---------- required by a bound introduced by this call
66
...
77
LL | arg: NotIntoDiagArg,
8-
| ^^^^^^^^^^^^^^ the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg`
8+
| ^^^^^^^^^^^^^^ unsatisfied trait bound
99
|
10+
help: the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg`
11+
--> $DIR/diagnostic-derive-doc-comment-field.rs:28:1
12+
|
13+
LL | struct NotIntoDiagArg;
14+
| ^^^^^^^^^^^^^^^^^^^^^
1015
= help: normalized in stderr
1116
note: required by a bound in `Diag::<'a, G>::arg`
1217
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC
@@ -19,8 +24,13 @@ LL | #[derive(Subdiagnostic)]
1924
| ------------- required by a bound introduced by this call
2025
...
2126
LL | arg: NotIntoDiagArg,
22-
| ^^^^^^^^^^^^^^ the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg`
27+
| ^^^^^^^^^^^^^^ unsatisfied trait bound
28+
|
29+
help: the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg`
30+
--> $DIR/diagnostic-derive-doc-comment-field.rs:28:1
2331
|
32+
LL | struct NotIntoDiagArg;
33+
| ^^^^^^^^^^^^^^^^^^^^^
2434
= help: normalized in stderr
2535
note: required by a bound in `Diag::<'a, G>::arg`
2636
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC

tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,13 @@ LL | #[derive(Diagnostic)]
637637
| ---------- required by a bound introduced by this call
638638
...
639639
LL | other: Hello,
640-
| ^^^^^ the trait `IntoDiagArg` is not implemented for `Hello`
640+
| ^^^^^ unsatisfied trait bound
641641
|
642+
help: the trait `IntoDiagArg` is not implemented for `Hello`
643+
--> $DIR/diagnostic-derive.rs:40:1
644+
|
645+
LL | struct Hello {}
646+
| ^^^^^^^^^^^^
642647
= help: normalized in stderr
643648
note: required by a bound in `Diag::<'a, G>::arg`
644649
--> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC

tests/ui/associated-consts/issue-105330.stderr

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
5353
--> $DIR/issue-105330.rs:12:11
5454
|
5555
LL | foo::<Demo>()();
56-
| ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
56+
| ^^^^ unsatisfied trait bound
5757
|
58+
help: the trait `TraitWAssocConst` is not implemented for `Demo`
59+
--> $DIR/issue-105330.rs:4:1
60+
|
61+
LL | pub struct Demo {}
62+
| ^^^^^^^^^^^^^^^
5863
note: required by a bound in `foo`
5964
--> $DIR/issue-105330.rs:11:11
6065
|
@@ -75,8 +80,13 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
7580
--> $DIR/issue-105330.rs:20:11
7681
|
7782
LL | foo::<Demo>();
78-
| ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
83+
| ^^^^ unsatisfied trait bound
84+
|
85+
help: the trait `TraitWAssocConst` is not implemented for `Demo`
86+
--> $DIR/issue-105330.rs:4:1
7987
|
88+
LL | pub struct Demo {}
89+
| ^^^^^^^^^^^^^^^
8090
note: required by a bound in `foo`
8191
--> $DIR/issue-105330.rs:11:11
8292
|

tests/ui/associated-types/defaults-suitability.current.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,13 @@ error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied
7373
--> $DIR/defaults-suitability.rs:59:18
7474
|
7575
LL | type Assoc = NotClone;
76-
| ^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone`
76+
| ^^^^^^^^ unsatisfied trait bound
7777
|
78+
help: the trait `IsU8<NotClone>` is not implemented for `NotClone`
79+
--> $DIR/defaults-suitability.rs:12:1
80+
|
81+
LL | struct NotClone;
82+
| ^^^^^^^^^^^^^^^
7883
note: required by a bound in `D::Assoc`
7984
--> $DIR/defaults-suitability.rs:56:18
8085
|

tests/ui/associated-types/defaults-suitability.next.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,13 @@ error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied
7373
--> $DIR/defaults-suitability.rs:59:18
7474
|
7575
LL | type Assoc = NotClone;
76-
| ^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone`
76+
| ^^^^^^^^ unsatisfied trait bound
7777
|
78+
help: the trait `IsU8<NotClone>` is not implemented for `NotClone`
79+
--> $DIR/defaults-suitability.rs:12:1
80+
|
81+
LL | struct NotClone;
82+
| ^^^^^^^^^^^^^^^
7883
note: required by a bound in `D::Assoc`
7984
--> $DIR/defaults-suitability.rs:56:18
8085
|

tests/ui/associated-types/issue-64855.stderr

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ error[E0277]: the trait bound `Bar<T>: Foo` is not satisfied
22
--> $DIR/issue-64855.rs:9:19
33
|
44
LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ;
5-
| ^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar<T>`
5+
| ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
66
|
7+
help: the trait `Foo` is not implemented for `Bar<T>`
8+
--> $DIR/issue-64855.rs:9:1
9+
|
10+
LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ;
11+
| ^^^^^^^^^^^^^^^^^
712
help: this trait has no implementations, consider adding one
813
--> $DIR/issue-64855.rs:5:1
914
|

0 commit comments

Comments
 (0)