mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #154154 - estebank:issue-134087, r=mati865
Emit fewer errors for incorrect rtn and `=` -> `:` typos in bindings Make all existing `:` -> `=` typo suggestions verbose and tweak the suggested code. Stash parse errors when pasing rtn that doesn't use `(..)`. Emit single error on `Foo::bar(qux)` that looks like rtn in incorrect position and suggest `Foo::bar(..)`. ``` error: return type notation not allowed in this position yet --> $DIR/let-binding-init-expr-as-ty.rs:18:10 | LL | struct K(S::new(())); | ^^^^^^^^^^ | help: furthermore, argument types not allowed with return type notation | LL - struct K(S::new(())); LL + struct K(S::new(..)); | ``` On incorrect rtn in let binding type for an existing inherent associated function, suggest `:` -> `=` to turn the "type" into a call expression. (Fix rust-lang/rust#134087) ``` error: expected type, found associated function call --> $DIR/let-binding-init-expr-as-ty.rs:29:12 | LL | let x: S::new(()); | ^^^^^^^^^^ | help: use `=` if you meant to assign | LL - let x: S::new(()); LL + let x = S::new(()); | ```
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_errors::StashKey;
|
||||
use rustc_hir::def::{DefKind, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, GenericArg};
|
||||
@@ -298,7 +299,7 @@ pub(crate) fn lower_path_segment(
|
||||
sym::return_type_notation,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
err.stash(path_span, StashKey::ReturnTypeNotation);
|
||||
(
|
||||
GenericArgsCtor {
|
||||
args: Default::default(),
|
||||
|
||||
@@ -386,6 +386,7 @@ pub enum StashKey {
|
||||
/// it's a method call without parens. If later on in `hir_typeck` we find out that this is
|
||||
/// the case we suppress this message and we give a better suggestion.
|
||||
GenericInFieldExpr,
|
||||
ReturnTypeNotation,
|
||||
}
|
||||
|
||||
fn default_track_diagnostic<R>(diag: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) -> R {
|
||||
|
||||
@@ -1807,6 +1807,13 @@ pub(crate) struct CmseImplTrait {
|
||||
pub(crate) struct BadReturnTypeNotation {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(
|
||||
"furthermore, argument types not allowed with return type notation",
|
||||
applicability = "maybe-incorrect",
|
||||
code = "(..)",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub suggestion: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, FatalError, Level,
|
||||
Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, FatalError, Level, StashKey,
|
||||
struct_span_code_err,
|
||||
};
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
@@ -3015,7 +3015,9 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
|
||||
}) =>
|
||||
{
|
||||
let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span });
|
||||
let guar = self
|
||||
.dcx()
|
||||
.emit_err(BadReturnTypeNotation { span: hir_ty.span, suggestion: None });
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(maybe_qself, path)) => {
|
||||
@@ -3077,12 +3079,95 @@ pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
|
||||
// If we encounter a type relative path with RTN generics, then it must have
|
||||
// *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
|
||||
// it's certainly in an illegal position.
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(_, segment))
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment))
|
||||
if segment.args.is_some_and(|args| {
|
||||
matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation)
|
||||
}) =>
|
||||
{
|
||||
let guar = self.dcx().emit_err(BadReturnTypeNotation { span: hir_ty.span });
|
||||
let guar = if let hir::Node::LetStmt(stmt) = tcx.parent_hir_node(hir_ty.hir_id)
|
||||
&& let None = stmt.init
|
||||
&& let hir::TyKind::Path(hir::QPath::Resolved(_, self_ty_path)) =
|
||||
hir_self_ty.kind
|
||||
&& let Res::Def(DefKind::Enum | DefKind::Struct | DefKind::Union, def_id) =
|
||||
self_ty_path.res
|
||||
&& let Some(_) = tcx
|
||||
.inherent_impls(def_id)
|
||||
.iter()
|
||||
.flat_map(|imp| {
|
||||
tcx.associated_items(*imp).filter_by_name_unhygienic(segment.ident.name)
|
||||
})
|
||||
.filter(|assoc| {
|
||||
matches!(assoc.kind, ty::AssocKind::Fn { has_self: false, .. })
|
||||
})
|
||||
.next()
|
||||
{
|
||||
// `let x: S::new(valid_in_ty_ctxt);` -> `let x = S::new(valid_in_ty_ctxt);`
|
||||
let err = tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
hir_ty.span,
|
||||
"expected type, found associated function call",
|
||||
)
|
||||
.with_span_suggestion_verbose(
|
||||
stmt.pat.span.between(hir_ty.span),
|
||||
"use `=` if you meant to assign",
|
||||
" = ".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
self.dcx().try_steal_replace_and_emit_err(
|
||||
hir_ty.span,
|
||||
StashKey::ReturnTypeNotation,
|
||||
err,
|
||||
)
|
||||
} else if let hir::Node::LetStmt(stmt) = tcx.parent_hir_node(hir_ty.hir_id)
|
||||
&& let None = stmt.init
|
||||
&& let hir::TyKind::Path(hir::QPath::Resolved(_, self_ty_path)) =
|
||||
hir_self_ty.kind
|
||||
&& let Res::PrimTy(_) = self_ty_path.res
|
||||
&& self.dcx().has_stashed_diagnostic(hir_ty.span, StashKey::ReturnTypeNotation)
|
||||
{
|
||||
// `let x: i32::something(valid_in_ty_ctxt);` -> `let x = i32::something(valid_in_ty_ctxt);`
|
||||
// FIXME: Check that `something` is a valid function in `i32`.
|
||||
let err = tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
hir_ty.span,
|
||||
"expected type, found associated function call",
|
||||
)
|
||||
.with_span_suggestion_verbose(
|
||||
stmt.pat.span.between(hir_ty.span),
|
||||
"use `=` if you meant to assign",
|
||||
" = ".to_string(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
self.dcx().try_steal_replace_and_emit_err(
|
||||
hir_ty.span,
|
||||
StashKey::ReturnTypeNotation,
|
||||
err,
|
||||
)
|
||||
} else {
|
||||
let suggestion = if self
|
||||
.dcx()
|
||||
.has_stashed_diagnostic(hir_ty.span, StashKey::ReturnTypeNotation)
|
||||
{
|
||||
// We already created a diagnostic complaining that `foo(bar)` is wrong and
|
||||
// should have been `foo(..)`. Instead, emit only the current error and
|
||||
// include that prior suggestion. Changes are that the problems go further,
|
||||
// but keep the suggestion just in case. Either way, we want a single error
|
||||
// instead of two.
|
||||
Some(segment.ident.span.shrink_to_hi().with_hi(hir_ty.span.hi()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let err = self
|
||||
.dcx()
|
||||
.create_err(BadReturnTypeNotation { span: hir_ty.span, suggestion });
|
||||
self.dcx().try_steal_replace_and_emit_err(
|
||||
hir_ty.span,
|
||||
StashKey::ReturnTypeNotation,
|
||||
err,
|
||||
)
|
||||
};
|
||||
Ty::new_error(tcx, guar)
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::TypeRelative(hir_self_ty, segment)) => {
|
||||
|
||||
@@ -362,7 +362,7 @@ fn parse_local(&mut self, super_: Option<Span>, attrs: AttrVec) -> PResult<'a, B
|
||||
// init parsed, ty error
|
||||
// Could parse the type as if it were the initializer, it is likely there was a
|
||||
// typo in the code: `:` instead of `=`. Add suggestion and emit the error.
|
||||
err.span_suggestion_short(
|
||||
err.span_suggestion_verbose(
|
||||
colon_sp,
|
||||
"use `=` if you meant to assign",
|
||||
" =",
|
||||
@@ -1133,11 +1133,11 @@ pub fn parse_full_stmt(
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if suggest_eq {
|
||||
e.span_suggestion_short(
|
||||
colon_sp,
|
||||
if suggest_eq && let Some(ty) = &local.ty {
|
||||
e.span_suggestion_verbose(
|
||||
local.pat.span.between(ty.span),
|
||||
"use `=` if you meant to assign",
|
||||
"=",
|
||||
" = ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1272,7 +1272,7 @@ fn suggest_typo(
|
||||
Some((pat_sp, Some(ty_sp), None))
|
||||
if ty_sp.contains(base_error.span) && base_error.could_be_expr =>
|
||||
{
|
||||
err.span_suggestion_short(
|
||||
err.span_suggestion_verbose(
|
||||
pat_sp.between(ty_sp),
|
||||
"use `=` if you meant to assign",
|
||||
" = ",
|
||||
|
||||
@@ -17,7 +17,12 @@ LL | let a: [i32, ];
|
||||
| - ^ expected `;` or `]`
|
||||
| |
|
||||
| while parsing the type for `a`
|
||||
| help: use `=` if you meant to assign
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let a: [i32, ];
|
||||
LL + let a = [i32, ];
|
||||
|
|
||||
|
||||
error: expected `;` or `]`, found `,`
|
||||
--> $DIR/array-type-no-semi.rs:12:16
|
||||
|
||||
@@ -13,7 +13,12 @@ LL | let _: std::env::temp_dir().join("foo");
|
||||
| - ^ expected one of `!`, `+`, `->`, `::`, `;`, or `=`
|
||||
| |
|
||||
| while parsing the type for `_`
|
||||
| help: use `=` if you meant to assign
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let _: std::env::temp_dir().join("foo");
|
||||
LL + let _ = std::env::temp_dir().join("foo");
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
||||
@@ -1,11 +1,41 @@
|
||||
pub fn foo(num: i32) -> i32 {
|
||||
fn foo(num: i32) -> i32 {
|
||||
// FIXME: This case doesn't really check that `from_be` is a valid function in `i32`.
|
||||
let foo: i32::from_be(num);
|
||||
//~^ ERROR expected type, found local variable `num`
|
||||
//~| ERROR argument types not allowed with return type notation
|
||||
//~| ERROR return type notation not allowed in this position yet
|
||||
//~| ERROR expected type, found associated function call
|
||||
foo
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn new(_: ()) -> S {
|
||||
S
|
||||
}
|
||||
}
|
||||
|
||||
// We should still mention that it should be `S::new(..)`, even though rtn is not allowed there:
|
||||
struct K(S::new(())); //~ ERROR return type notation not allowed in this position yet
|
||||
|
||||
fn bar() {}
|
||||
|
||||
fn main() {
|
||||
let _ = foo(42);
|
||||
// Associated functions (#134087)
|
||||
let x: Vec::new(); //~ ERROR expected type, found associated function call
|
||||
let x: Vec<()>::new(); //~ ERROR expected type, found associated function call
|
||||
let x: S::new(..); //~ ERROR expected type, found associated function call
|
||||
//~^ ERROR return type notation is experimental
|
||||
let x: S::new(()); //~ ERROR expected type, found associated function call
|
||||
|
||||
// Literals
|
||||
let x: 42; //~ ERROR expected type, found `42`
|
||||
let x: ""; //~ ERROR expected type, found `""`
|
||||
|
||||
// Functions
|
||||
let x: bar(); //~ ERROR expected type, found function `bar`
|
||||
let x: bar; //~ ERROR expected type, found function `bar`
|
||||
|
||||
// Locals
|
||||
let x: x; //~ ERROR expected type, found local variable `x`
|
||||
}
|
||||
|
||||
@@ -1,32 +1,159 @@
|
||||
error[E0573]: expected type, found local variable `num`
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:2:27
|
||||
error: expected type, found `42`
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:32:12
|
||||
|
|
||||
LL | let x: 42;
|
||||
| - ^^ expected type
|
||||
| |
|
||||
| while parsing the type for `x`
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let x: 42;
|
||||
LL + let x = 42;
|
||||
|
|
||||
LL | let foo: i32::from_be(num);
|
||||
| -- ^^^ not a type
|
||||
| |
|
||||
| help: use `=` if you meant to assign
|
||||
|
||||
error: argument types not allowed with return type notation
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:2:26
|
||||
error: expected type, found `""`
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:33:12
|
||||
|
|
||||
LL | let x: "";
|
||||
| - ^^ expected type
|
||||
| |
|
||||
| while parsing the type for `x`
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let x: "";
|
||||
LL + let x = "";
|
||||
|
|
||||
|
||||
error[E0573]: expected type, found local variable `num`
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:3:27
|
||||
|
|
||||
LL | let foo: i32::from_be(num);
|
||||
| ^^^^^
|
||||
| ^^^ not a type
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let foo: i32::from_be(num);
|
||||
LL + let foo = i32::from_be(num);
|
||||
|
|
||||
|
||||
error[E0573]: expected type, found function `bar`
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:36:12
|
||||
|
|
||||
LL | let x: bar();
|
||||
| ^^^^^ not a type
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let x: bar();
|
||||
LL + let x = bar();
|
||||
|
|
||||
|
||||
error[E0573]: expected type, found function `bar`
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:37:12
|
||||
|
|
||||
LL | let x: bar;
|
||||
| ^^^ not a type
|
||||
|
||||
error[E0573]: expected type, found local variable `x`
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:40:12
|
||||
|
|
||||
LL | struct K(S::new(()));
|
||||
| --------------------- similarly named struct `K` defined here
|
||||
...
|
||||
LL | let x: x;
|
||||
| ^
|
||||
|
|
||||
help: a struct with a similar name exists
|
||||
|
|
||||
LL - let x: x;
|
||||
LL + let x: K;
|
||||
|
|
||||
|
||||
error[E0658]: return type notation is experimental
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:27:18
|
||||
|
|
||||
LL | let x: S::new(..);
|
||||
| ^^^^
|
||||
|
|
||||
= note: see issue #109417 <https://github.com/rust-lang/rust/issues/109417> for more information
|
||||
= help: add `#![feature(return_type_notation)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
help: remove the input types
|
||||
|
|
||||
LL - let foo: i32::from_be(num);
|
||||
LL + let foo: i32::from_be(..);
|
||||
|
|
||||
|
||||
error: return type notation not allowed in this position yet
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:2:14
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:18:10
|
||||
|
|
||||
LL | struct K(S::new(()));
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
help: furthermore, argument types not allowed with return type notation
|
||||
|
|
||||
LL - struct K(S::new(()));
|
||||
LL + struct K(S::new(..));
|
||||
|
|
||||
|
||||
error: expected type, found associated function call
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:3:14
|
||||
|
|
||||
LL | let foo: i32::from_be(num);
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let foo: i32::from_be(num);
|
||||
LL + let foo = i32::from_be(num);
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: expected type, found associated function call
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:25:12
|
||||
|
|
||||
LL | let x: Vec::new();
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let x: Vec::new();
|
||||
LL + let x = Vec::new();
|
||||
|
|
||||
|
||||
For more information about this error, try `rustc --explain E0573`.
|
||||
error: expected type, found associated function call
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:26:12
|
||||
|
|
||||
LL | let x: Vec<()>::new();
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let x: Vec<()>::new();
|
||||
LL + let x = Vec<()>::new();
|
||||
|
|
||||
|
||||
error: expected type, found associated function call
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:27:12
|
||||
|
|
||||
LL | let x: S::new(..);
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let x: S::new(..);
|
||||
LL + let x = S::new(..);
|
||||
|
|
||||
|
||||
error: expected type, found associated function call
|
||||
--> $DIR/let-binding-init-expr-as-ty.rs:29:12
|
||||
|
|
||||
LL | let x: S::new(());
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let x: S::new(());
|
||||
LL + let x = S::new(());
|
||||
|
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0573, E0658.
|
||||
For more information about an error, try `rustc --explain E0573`.
|
||||
|
||||
@@ -5,7 +5,12 @@ LL | let x: Vec::with_capacity(10, 20);
|
||||
| - ^^ expected type
|
||||
| |
|
||||
| while parsing the type for `x`
|
||||
| help: use `=` if you meant to assign
|
||||
|
|
||||
help: use `=` if you meant to assign
|
||||
|
|
||||
LL - let x: Vec::with_capacity(10, 20);
|
||||
LL + let x = Vec::with_capacity(10, 20);
|
||||
|
|
||||
|
||||
error[E0061]: this function takes 1 argument but 2 arguments were supplied
|
||||
--> $DIR/type-ascription-instead-of-initializer.rs:2:12
|
||||
|
||||
Reference in New Issue
Block a user