diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-11-17 00:41:23 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-17 00:41:23 +0100 |
| commit | dd49c39e0223e3c134a9c36132dda6572a1b0374 (patch) | |
| tree | f3f9a3937c25c2a3c30e6ba0e00d735fede29830 | |
| parent | 92aba63d6b46dbcf50b544c6cef8b85d8713aa09 (diff) | |
| parent | 1e8c0951e93566312240ab0f80c8387e2b549a3e (diff) | |
| download | rust-dd49c39e0223e3c134a9c36132dda6572a1b0374.tar.gz rust-dd49c39e0223e3c134a9c36132dda6572a1b0374.zip | |
Rollup merge of #117959 - estebank:issue-76086, r=compiler-errors
Better handle type errors involving `Self` literals
When encountering a type error involving a `Self` literal, point at the self type of the enclosing `impl` and suggest using the actual type name instead.
```
error[E0308]: mismatched types
--> $DIR/struct-path-self-type-mismatch.rs:13:9
|
LL | impl<T> Foo<T> {
| - ------ this is the type of the `Self` literal
| |
| found type parameter
LL | fn new<U>(u: U) -> Foo<U> {
| - ------ expected `Foo<U>` because of return type
| |
| expected type parameter
LL | / Self {
LL | |
LL | | inner: u
LL | |
LL | | }
| |_________^ expected `Foo<U>`, found `Foo<T>`
|
= note: expected struct `Foo<U>`
found struct `Foo<T>`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
help: use the type name directly
|
LL | Foo::<U> {
| ~~~~~~~~
```
Fix #76086.
| -rw-r--r-- | compiler/rustc_hir_typeck/src/demand.rs | 54 | ||||
| -rw-r--r-- | tests/ui/structs/struct-path-self-type-mismatch.stderr | 8 |
2 files changed, 61 insertions, 1 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 77d6183f862..386e4b4642a 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -31,6 +31,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } self.annotate_alternative_method_deref(err, expr, error); + self.explain_self_literal(err, expr, expected, expr_ty); // Use `||` to give these suggestions a precedence let suggested = self.suggest_missing_parentheses(err, expr) @@ -1027,6 +1028,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } + fn explain_self_literal( + &self, + err: &mut Diagnostic, + expr: &hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + match expr.peel_drop_temps().kind { + hir::ExprKind::Struct( + hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, span, .. }, + ), + .., + ) + | hir::ExprKind::Call( + hir::Expr { + kind: + hir::ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { + res: hir::def::Res::SelfTyAlias { alias_to, .. }, + span, + .. + }, + )), + .. + }, + .., + ) => { + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }), + .. + })) = self.tcx.hir().get_if_local(*alias_to) + { + err.span_label(self_ty.span, "this is the type of the `Self` literal"); + } + if let ty::Adt(e_def, e_args) = expected.kind() + && let ty::Adt(f_def, _f_args) = found.kind() + && e_def == f_def + { + err.span_suggestion_verbose( + *span, + "use the type name directly", + self.tcx.value_path_str_with_args(*alias_to, e_args), + Applicability::MaybeIncorrect, + ); + } + } + _ => {} + } + } + fn note_wrong_return_ty_due_to_generic_arg( &self, err: &mut Diagnostic, diff --git a/tests/ui/structs/struct-path-self-type-mismatch.stderr b/tests/ui/structs/struct-path-self-type-mismatch.stderr index cddc1356194..bbe5bae29bb 100644 --- a/tests/ui/structs/struct-path-self-type-mismatch.stderr +++ b/tests/ui/structs/struct-path-self-type-mismatch.stderr @@ -24,7 +24,9 @@ error[E0308]: mismatched types --> $DIR/struct-path-self-type-mismatch.rs:13:9 | LL | impl<T> Foo<T> { - | - found type parameter + | - ------ this is the type of the `Self` literal + | | + | found type parameter LL | fn new<U>(u: U) -> Foo<U> { | - ------ expected `Foo<U>` because of return type | | @@ -40,6 +42,10 @@ LL | | } found struct `Foo<T>` = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters +help: use the type name directly + | +LL | Foo::<U> { + | ~~~~~~~~ error: aborting due to 3 previous errors |
