Skip to content

Commit 20f4e5d

Browse files
committed
Detect turbofish missing surrounding angle brackets
1 parent 9e92106 commit 20f4e5d

File tree

5 files changed

+61
-3
lines changed

5 files changed

+61
-3
lines changed

src/librustc_parse/parser/diagnostics.rs

+41-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use super::ty::AllowPlus;
22
use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
33

44
use rustc_ast::ast::{self, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Item, Param};
5-
use rustc_ast::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
5+
use rustc_ast::ast::{
6+
AngleBracketedArgs, AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind,
7+
};
68
use rustc_ast::ptr::P;
79
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
810
use rustc_ast::util::parser::AssocOp;
@@ -488,6 +490,44 @@ impl<'a> Parser<'a> {
488490
false
489491
}
490492

493+
/// Check if a method call with an intended turbofish has been written without surrounding
494+
/// angle brackets.
495+
pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
496+
if token::ModSep == self.token.kind && segment.args.is_none() {
497+
let snapshot = self.clone();
498+
self.bump();
499+
let lo = self.token.span;
500+
match self.parse_angle_args() {
501+
Ok(args) if self.token.kind == token::OpenDelim(token::Paren) => {
502+
// Recover from bad turbofish: `foo.collect::Vec<_>()`.
503+
let span = lo.to(self.prev_token.span);
504+
let args = AngleBracketedArgs { args, span }.into();
505+
segment.args = args;
506+
self.struct_span_err(
507+
span,
508+
"generic parameters without surrounding angle brackets",
509+
)
510+
.multipart_suggestion(
511+
"surround the type parameters with angle brackets",
512+
vec![
513+
(span.shrink_to_lo(), "<".to_string()),
514+
(span.shrink_to_hi(), ">".to_string()),
515+
],
516+
Applicability::MachineApplicable,
517+
)
518+
.emit();
519+
}
520+
Ok(_) => {
521+
*self = snapshot;
522+
}
523+
Err(mut err) => {
524+
err.cancel();
525+
*self = snapshot;
526+
}
527+
}
528+
}
529+
}
530+
491531
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
492532
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
493533
/// parenthesising the leftmost comparison.

src/librustc_parse/parser/expr.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -909,8 +909,9 @@ impl<'a> Parser<'a> {
909909
}
910910

911911
let fn_span_lo = self.token.span;
912-
let segment = self.parse_path_segment(PathStyle::Expr)?;
912+
let mut segment = self.parse_path_segment(PathStyle::Expr)?;
913913
self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
914+
self.check_turbofish_missing_angle_brackets(&mut segment);
914915

915916
if self.check(&token::OpenDelim(token::Paren)) {
916917
// Method call `expr.f()`

src/librustc_parse/parser/path.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ impl<'a> Parser<'a> {
387387

388388
/// Parses (possibly empty) list of generic arguments / associated item constraints,
389389
/// possibly including trailing comma.
390-
fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
390+
pub(super) fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
391391
let mut args = Vec::new();
392392
while let Some(arg) = self.parse_angle_arg()? {
393393
args.push(arg);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
let _ = vec![1, 2, 3].into_iter().collect::Vec<_>();
3+
//~^ ERROR generic parameters without surrounding angle brackets
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error: generic parameters without surrounding angle brackets
2+
--> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:2:48
3+
|
4+
LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>();
5+
| ^^^^^^
6+
|
7+
help: surround the type parameters with angle brackets
8+
|
9+
LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
10+
| ^ ^
11+
12+
error: aborting due to previous error
13+

0 commit comments

Comments
 (0)