Skip to content

Commit 15eedde

Browse files
authored
Rollup merge of #145641 - estebank:point-at-type-in-e0277, r=davidtwco
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: ; | ^^^^^^^^^^^^^^^^^ ```
2 parents 6991786 + 049c327 commit 15eedde

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)