about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-11-17 00:41:23 +0100
committerGitHub <noreply@github.com>2023-11-17 00:41:23 +0100
commitdd49c39e0223e3c134a9c36132dda6572a1b0374 (patch)
treef3f9a3937c25c2a3c30e6ba0e00d735fede29830
parent92aba63d6b46dbcf50b544c6cef8b85d8713aa09 (diff)
parent1e8c0951e93566312240ab0f80c8387e2b549a3e (diff)
downloadrust-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.rs54
-rw-r--r--tests/ui/structs/struct-path-self-type-mismatch.stderr8
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