Show type param definitions in type mismatch errors

Fixes #47319.

Shows the type parameter definition(s) on type mismatch errors so the
context is clearer. Pretty much changes the following:

```
LL |     bar1(t);
   |          ^
   |          |
   |          expected enum `std::option::Option`, found type parameter `T`
```

into:

```
LL | fn foo1<T>(t: T) {
   |         - this type parameter
LL |     bar1(t);
   |          ^
   |          |
   |          expected enum `std::option::Option`, found type parameter `T`
```
This commit is contained in:
Dmitry Kadashev 2019-10-31 17:20:33 +07:00
parent 6a30ce639f
commit 036f182804
2 changed files with 26 additions and 3 deletions

View File

@ -1190,8 +1190,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
// In some (most?) cases cause.body_id points to actual body, but in some cases
// it's a actual definition. According to the comments (e.g. in
// librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
// is relied upon by some other code. This might (or might not) need cleanup.
let body_owner_def_id = match self.tcx.hir().opt_local_def_id(cause.body_id) {
Some(def_id) => def_id,
None => self.tcx.hir().body_owner_def_id(hir::BodyId{hir_id: cause.body_id}),
};
self.check_and_note_conflicting_crates(diag, terr, span);
self.tcx.note_and_explain_type_err(diag, terr, span);
self.tcx.note_and_explain_type_err(diag, terr, span, body_owner_def_id);
// It reads better to have the error origin as the final
// thing.

View File

@ -254,6 +254,7 @@ impl<'tcx> TyCtxt<'tcx> {
db: &mut DiagnosticBuilder<'_>,
err: &TypeError<'tcx>,
sp: Span,
body_owner_def_id: DefId,
) {
use self::TypeError::*;
@ -288,7 +289,16 @@ impl<'tcx> TyCtxt<'tcx> {
);
}
},
(ty::Param(_), ty::Param(_)) => {
(ty::Param(expected), ty::Param(found)) => {
let generics = self.generics_of(body_owner_def_id);
db.span_label(
self.def_span(generics.type_param(expected, self).def_id),
"expected type parameter"
);
db.span_label(
self.def_span(generics.type_param(found, self).def_id),
"found type parameter"
);
db.note("a type parameter was expected, but a different one was found; \
you might be missing a type parameter or trait bound");
db.note("for more information, visit \
@ -301,7 +311,12 @@ impl<'tcx> TyCtxt<'tcx> {
(ty::Param(_), ty::Projection(_)) | (ty::Projection(_), ty::Param(_)) => {
db.note("you might be missing a type parameter or trait bound");
}
(ty::Param(_), _) | (_, ty::Param(_)) => {
(ty::Param(p), _) | (_, ty::Param(p)) => {
let generics = self.generics_of(body_owner_def_id);
db.span_label(
self.def_span(generics.type_param(p, self).def_id),
"this type parameter"
);
db.help("type parameters must be constrained to match other types");
if self.sess.teach(&db.get_code().unwrap()) {
db.help("given a type parameter `T` and a method `foo`: