From a7e035ab899be54fda12c6bae6ef7ecbcce0aaea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Nov 2023 01:41:58 +0000 Subject: [PATCH 1/3] Point at impl self ty on type error involving `Self` When encountering a type error involving a `Self` literal, point at the self type of the enclosing `impl`. CC #76086. --- compiler/rustc_hir_typeck/src/coercion.rs | 38 +++++++++++++++++++ .../struct-path-self-type-mismatch.stderr | 4 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6c03bc3b57ac6..58f4e07e9446e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1738,6 +1738,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); 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) = ( @@ -1810,6 +1811,43 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err } + fn explain_self_literal( + &self, + fcx: &FnCtxt<'_, 'tcx>, + err: &mut Diagnostic, + expr: &'tcx hir::Expr<'tcx>, + ) { + match expr.peel_drop_temps().kind { + hir::ExprKind::Struct( + hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, .. }, + ), + .., + ) + | hir::ExprKind::Call( + hir::Expr { + kind: + hir::ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { res: hir::def::Res::SelfTyAlias { alias_to, .. }, .. }, + )), + .. + }, + .., + ) => { + if let Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { self_ty, .. }), + .. + })) = fcx.tcx.hir().get_if_local(*alias_to) + { + err.span_label(self_ty.span, "this is the type of the `Self` literal"); + } + } + _ => {} + } + } + /// Checks whether the return type is unsized via an obligation, which makes /// sure we consider `dyn Trait: Sized` where clauses, which are trivially /// false but technically valid for typeck. diff --git a/tests/ui/structs/struct-path-self-type-mismatch.stderr b/tests/ui/structs/struct-path-self-type-mismatch.stderr index cddc1356194bf..f4ca485108307 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 Foo { - | - found type parameter + | - ------ this is the type of the `Self` literal + | | + | found type parameter LL | fn new(u: U) -> Foo { | - ------ expected `Foo` because of return type | | From d8456855f5d65a2ed26b09a82c750535a09becdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Nov 2023 02:27:55 +0000 Subject: [PATCH 2/3] Suggest replacing `Self` with the right type on type error 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 Foo { | - ------ this is the type of the `Self` literal | | | found type parameter LL | fn new(u: U) -> Foo { | - ------ expected `Foo` because of return type | | | expected type parameter LL | / Self { LL | | LL | | inner: u LL | | LL | | } | |_________^ expected `Foo`, found `Foo` | = note: expected struct `Foo` found struct `Foo` = 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:: { | ~~~~~~~~ ``` Fix #76086. --- compiler/rustc_hir_typeck/src/coercion.rs | 27 ++++++++++++++++--- .../struct-path-self-type-mismatch.stderr | 4 +++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 58f4e07e9446e..8dbf01e973544 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -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}; @@ -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) = ( @@ -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, .. }, ), .., ) @@ -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, + .. + }, )), .. }, @@ -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() + && let 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, + ); + } } _ => {} } diff --git a/tests/ui/structs/struct-path-self-type-mismatch.stderr b/tests/ui/structs/struct-path-self-type-mismatch.stderr index f4ca485108307..bbe5bae29bbe1 100644 --- a/tests/ui/structs/struct-path-self-type-mismatch.stderr +++ b/tests/ui/structs/struct-path-self-type-mismatch.stderr @@ -42,6 +42,10 @@ LL | | } found struct `Foo` = 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:: { + | ~~~~~~~~ error: aborting due to 3 previous errors From 1e8c0951e93566312240ab0f80c8387e2b549a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 16 Nov 2023 21:30:26 +0000 Subject: [PATCH 3/3] review comment: move error logic to different method --- compiler/rustc_hir_typeck/src/coercion.rs | 59 +---------------------- compiler/rustc_hir_typeck/src/demand.rs | 54 +++++++++++++++++++++ 2 files changed, 55 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 8dbf01e973544..6c03bc3b57ac6 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -36,9 +36,7 @@ //! ``` use crate::FnCtxt; -use rustc_errors::{ - struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan, -}; +use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -1740,7 +1738,6 @@ 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, 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) = ( @@ -1813,60 +1810,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { err } - fn explain_self_literal( - &self, - 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, .. }, 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, .. }), - .. - })) = fcx.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", - fcx.tcx.value_path_str_with_args(*alias_to, e_args), - Applicability::MaybeIncorrect, - ); - } - } - _ => {} - } - } - /// Checks whether the return type is unsized via an obligation, which makes /// sure we consider `dyn Trait: Sized` where clauses, which are trivially /// false but technically valid for typeck. diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 77d6183f862f5..386e4b4642a82 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,