Auto merge of #76171 - estebank:turbofish-the-revenge, r=davidtwco
Detect turbofish with multiple type params missing leading `::` Fix #76072.
This commit is contained in:
commit
90b1f5ae59
@ -553,6 +553,52 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When writing a turbofish with multiple type parameters missing the leading `::`, we will
|
||||||
|
/// encounter a parse error when encountering the first `,`.
|
||||||
|
pub(super) fn check_mistyped_turbofish_with_multiple_type_params(
|
||||||
|
&mut self,
|
||||||
|
mut e: DiagnosticBuilder<'a>,
|
||||||
|
expr: &mut P<Expr>,
|
||||||
|
) -> PResult<'a, ()> {
|
||||||
|
if let ExprKind::Binary(binop, _, _) = &expr.kind {
|
||||||
|
if let ast::BinOpKind::Lt = binop.node {
|
||||||
|
if self.eat(&token::Comma) {
|
||||||
|
let x = self.parse_seq_to_before_end(
|
||||||
|
&token::Gt,
|
||||||
|
SeqSep::trailing_allowed(token::Comma),
|
||||||
|
|p| p.parse_ty(),
|
||||||
|
);
|
||||||
|
match x {
|
||||||
|
Ok((_, _, false)) => {
|
||||||
|
self.bump(); // `>`
|
||||||
|
match self.parse_expr() {
|
||||||
|
Ok(_) => {
|
||||||
|
e.span_suggestion_verbose(
|
||||||
|
binop.span.shrink_to_lo(),
|
||||||
|
"use `::<...>` instead of `<...>` to specify type arguments",
|
||||||
|
"::".to_string(),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
e.emit();
|
||||||
|
*expr = self.mk_expr_err(expr.span.to(self.prev_token.span));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(mut err) => {
|
||||||
|
err.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(mut err) => {
|
||||||
|
err.cancel();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
|
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
|
||||||
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
|
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
|
||||||
/// parenthesising the leftmost comparison.
|
/// parenthesising the leftmost comparison.
|
||||||
|
@ -364,7 +364,7 @@ impl<'a> Parser<'a> {
|
|||||||
let mut eat_semi = true;
|
let mut eat_semi = true;
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
// Expression without semicolon.
|
// Expression without semicolon.
|
||||||
StmtKind::Expr(ref expr)
|
StmtKind::Expr(ref mut expr)
|
||||||
if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
|
if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
|
||||||
{
|
{
|
||||||
// Just check for errors and recover; do not eat semicolon yet.
|
// Just check for errors and recover; do not eat semicolon yet.
|
||||||
@ -388,15 +388,29 @@ impl<'a> Parser<'a> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e.emit();
|
if let Err(mut e) =
|
||||||
self.recover_stmt();
|
self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
|
||||||
|
{
|
||||||
|
e.emit();
|
||||||
|
self.recover_stmt();
|
||||||
|
}
|
||||||
// Don't complain about type errors in body tail after parse error (#57383).
|
// Don't complain about type errors in body tail after parse error (#57383).
|
||||||
let sp = expr.span.to(self.prev_token.span);
|
let sp = expr.span.to(self.prev_token.span);
|
||||||
stmt.kind = StmtKind::Expr(self.mk_expr_err(sp));
|
*expr = self.mk_expr_err(sp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Local(..) => {
|
StmtKind::Local(ref mut local) => {
|
||||||
self.expect_semi()?;
|
if let Err(e) = self.expect_semi() {
|
||||||
|
// We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
|
||||||
|
match &mut local.init {
|
||||||
|
Some(ref mut expr) => {
|
||||||
|
self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?;
|
||||||
|
// We found `foo<bar, baz>`, have we fully recovered?
|
||||||
|
self.expect_semi()?;
|
||||||
|
}
|
||||||
|
None => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
eat_semi = false;
|
eat_semi = false;
|
||||||
}
|
}
|
||||||
StmtKind::Empty => eat_semi = false,
|
StmtKind::Empty => eat_semi = false,
|
||||||
|
@ -1,8 +1,29 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
(0..13).collect<Vec<i32>>();
|
(0..13).collect<Vec<i32>>();
|
||||||
//~^ ERROR comparison operators cannot be chained
|
//~^ ERROR comparison operators cannot be chained
|
||||||
|
//~| HELP use `::<...>` instead
|
||||||
Vec<i32>::new();
|
Vec<i32>::new();
|
||||||
//~^ ERROR comparison operators cannot be chained
|
//~^ ERROR comparison operators cannot be chained
|
||||||
|
//~| HELP use `::<...>` instead
|
||||||
(0..13).collect<Vec<i32>();
|
(0..13).collect<Vec<i32>();
|
||||||
//~^ ERROR comparison operators cannot be chained
|
//~^ ERROR comparison operators cannot be chained
|
||||||
|
//~| HELP use `::<...>` instead
|
||||||
|
let x = std::collections::HashMap<i128, i128>::new(); //~ ERROR expected one of
|
||||||
|
//~^ HELP use `::<...>` instead
|
||||||
|
let x: () = 42; //~ ERROR mismatched types
|
||||||
|
let x = {
|
||||||
|
std::collections::HashMap<i128, i128>::new() //~ ERROR expected one of
|
||||||
|
//~^ HELP use `::<...>` instead
|
||||||
|
};
|
||||||
|
let x: () = 42; //~ ERROR mismatched types
|
||||||
|
let x = {
|
||||||
|
std::collections::HashMap<i128, i128>::new(); //~ ERROR expected one of
|
||||||
|
//~^ HELP use `::<...>` instead
|
||||||
|
let x: () = 42; //~ ERROR mismatched types
|
||||||
|
};
|
||||||
|
{
|
||||||
|
std::collections::HashMap<i128, i128>::new(1, 2); //~ ERROR expected one of
|
||||||
|
//~^ HELP use `::<...>` instead
|
||||||
|
let x: () = 32; //~ ERROR mismatched types
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ LL | (0..13).collect::<Vec<i32>>();
|
|||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: comparison operators cannot be chained
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/issue-40396.rs:4:8
|
--> $DIR/issue-40396.rs:5:8
|
||||||
|
|
|
|
||||||
LL | Vec<i32>::new();
|
LL | Vec<i32>::new();
|
||||||
| ^ ^
|
| ^ ^
|
||||||
@ -21,7 +21,7 @@ LL | Vec::<i32>::new();
|
|||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: comparison operators cannot be chained
|
error: comparison operators cannot be chained
|
||||||
--> $DIR/issue-40396.rs:6:20
|
--> $DIR/issue-40396.rs:8:20
|
||||||
|
|
|
|
||||||
LL | (0..13).collect<Vec<i32>();
|
LL | (0..13).collect<Vec<i32>();
|
||||||
| ^ ^
|
| ^ ^
|
||||||
@ -31,5 +31,82 @@ help: use `::<...>` instead of `<...>` to specify type arguments
|
|||||||
LL | (0..13).collect::<Vec<i32>();
|
LL | (0..13).collect::<Vec<i32>();
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,`
|
||||||
|
--> $DIR/issue-40396.rs:11:43
|
||||||
|
|
|
||||||
|
LL | let x = std::collections::HashMap<i128, i128>::new();
|
||||||
|
| ^ expected one of 7 possible tokens
|
||||||
|
|
|
||||||
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
||||||
|
LL | let x = std::collections::HashMap::<i128, i128>::new();
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
|
||||||
|
--> $DIR/issue-40396.rs:15:39
|
||||||
|
|
|
||||||
|
LL | std::collections::HashMap<i128, i128>::new()
|
||||||
|
| ^ expected one of 8 possible tokens
|
||||||
|
|
|
||||||
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
||||||
|
LL | std::collections::HashMap::<i128, i128>::new()
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
|
||||||
|
--> $DIR/issue-40396.rs:20:39
|
||||||
|
|
|
||||||
|
LL | std::collections::HashMap<i128, i128>::new();
|
||||||
|
| ^ expected one of 8 possible tokens
|
||||||
|
|
|
||||||
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
||||||
|
LL | std::collections::HashMap::<i128, i128>::new();
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
|
||||||
|
--> $DIR/issue-40396.rs:25:39
|
||||||
|
|
|
||||||
|
LL | std::collections::HashMap<i128, i128>::new(1, 2);
|
||||||
|
| ^ expected one of 8 possible tokens
|
||||||
|
|
|
||||||
|
help: use `::<...>` instead of `<...>` to specify type arguments
|
||||||
|
|
|
||||||
|
LL | std::collections::HashMap::<i128, i128>::new(1, 2);
|
||||||
|
| ^^
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-40396.rs:13:17
|
||||||
|
|
|
||||||
|
LL | let x: () = 42;
|
||||||
|
| -- ^^ expected `()`, found integer
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-40396.rs:18:17
|
||||||
|
|
|
||||||
|
LL | let x: () = 42;
|
||||||
|
| -- ^^ expected `()`, found integer
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-40396.rs:22:21
|
||||||
|
|
|
||||||
|
LL | let x: () = 42;
|
||||||
|
| -- ^^ expected `()`, found integer
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/issue-40396.rs:27:21
|
||||||
|
|
|
||||||
|
LL | let x: () = 32;
|
||||||
|
| -- ^^ expected `()`, found integer
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
||||||
|
error: aborting due to 11 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
Loading…
Reference in New Issue
Block a user