Skip to content

Commit

Permalink
Detect turbofish with multiple type params missing leading ::
Browse files Browse the repository at this point in the history
Fix #76072.
  • Loading branch information
estebank committed Sep 14, 2020
1 parent 85fbf49 commit 62effcb
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 9 deletions.
46 changes: 46 additions & 0 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Expand Up @@ -548,6 +548,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,
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
/// parenthesising the leftmost comparison.
Expand Down
26 changes: 20 additions & 6 deletions compiler/rustc_parse/src/parser/stmt.rs
Expand Up @@ -363,7 +363,7 @@ impl<'a> Parser<'a> {
let mut eat_semi = true;
match stmt.kind {
// 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) =>
{
// Just check for errors and recover; do not eat semicolon yet.
Expand All @@ -387,15 +387,29 @@ impl<'a> Parser<'a> {
);
}
}
e.emit();
self.recover_stmt();
if let Err(mut e) =
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).
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(..) => {
self.expect_semi()?;
StmtKind::Local(ref mut local) => {
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;
}
StmtKind::Empty => eat_semi = false,
Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/did_you_mean/issue-40396.rs
@@ -1,8 +1,29 @@
fn main() {
(0..13).collect<Vec<i32>>();
//~^ ERROR comparison operators cannot be chained
//~| HELP use `::<...>` instead
Vec<i32>::new();
//~^ ERROR comparison operators cannot be chained
//~| HELP use `::<...>` instead
(0..13).collect<Vec<i32>();
//~^ 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
};
}
83 changes: 80 additions & 3 deletions src/test/ui/did_you_mean/issue-40396.stderr
Expand Up @@ -10,7 +10,7 @@ LL | (0..13).collect::<Vec<i32>>();
| ^^

error: comparison operators cannot be chained
--> $DIR/issue-40396.rs:4:8
--> $DIR/issue-40396.rs:5:8
|
LL | Vec<i32>::new();
| ^ ^
Expand All @@ -21,7 +21,7 @@ LL | Vec::<i32>::new();
| ^^

error: comparison operators cannot be chained
--> $DIR/issue-40396.rs:6:20
--> $DIR/issue-40396.rs:8:20
|
LL | (0..13).collect<Vec<i32>();
| ^ ^
Expand All @@ -31,5 +31,82 @@ help: use `::<...>` instead of `<...>` to specify type arguments
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`.

0 comments on commit 62effcb

Please sign in to comment.