Skip to content

Commit

Permalink
Suggest replacing Self with the right type on type error
Browse files Browse the repository at this point in the history
When encountering a type error caused by the use of `Self`, 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 rust-lang#76086.
  • Loading branch information
estebank committed Nov 16, 2023
1 parent e5aa9cc commit 38faceb
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 4 deletions.
27 changes: 23 additions & 4 deletions compiler/rustc_hir_typeck/src/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@
//! ```
use crate::FnCtxt;
use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
Expand Down Expand Up @@ -1738,7 +1740,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
// label pointing out the cause for the type coercion will be wrong
// as prior return coercions would not be relevant (#57664).
let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
self.explain_self_literal(fcx, &mut err, expr);
self.explain_self_literal(fcx, &mut err, expr, expected, found);
let pointing_at_return_type =
fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
if let (Some(cond_expr), true, false) = (
Expand Down Expand Up @@ -1816,12 +1818,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
fcx: &FnCtxt<'_, 'tcx>,
err: &mut Diagnostic,
expr: &'tcx 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, .. }, .. },
hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, span, .. },
),
..,
)
Expand All @@ -1830,7 +1834,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
kind:
hir::ExprKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, .. },
hir::Path {
res: hir::def::Res::SelfTyAlias { alias_to, .. },
span,
..
},
)),
..
},
Expand All @@ -1843,6 +1851,17 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
{
err.span_label(self_ty.span, "this is the type of the `Self` literal");
}
if let ty::Adt(e_def, e_args) = expected.kind()
&& ty::Adt(f_def, _f_args) = found.kind()
&& e_def == f_def
{
err.span_suggestion_verbose(
*span,
"use the type name directly",
fcx.tcx.value_path_str_with_args(*alias_to, e_args),
Applicability::MaybeIncorrect,
);
}
}
_ => {}
}
Expand Down
4 changes: 4 additions & 0 deletions tests/ui/structs/struct-path-self-type-mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -42,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

Expand Down

0 comments on commit 38faceb

Please sign in to comment.