Skip to content

Commit f06e8e1

Browse files
committed
Auto merge of #74687 - estebank:bracketless-turbofish, r=matthewjasper
Detect turbofish missing surrounding angle brackets Fix #74065.
2 parents fe08fb7 + d090e5e commit f06e8e1

File tree

5 files changed

+114
-4
lines changed

5 files changed

+114
-4
lines changed

src/librustc_parse/parser/diagnostics.rs

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

4-
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};
4+
use rustc_ast::ast::{
5+
self, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind,
6+
Item, ItemKind, Mutability, Param, 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,57 @@ 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) => {
502+
let span = lo.to(self.prev_token.span);
503+
// Detect trailing `>` like in `x.collect::Vec<_>>()`.
504+
let mut trailing_span = self.prev_token.span.shrink_to_hi();
505+
while self.token.kind == token::BinOp(token::Shr)
506+
|| self.token.kind == token::Gt
507+
{
508+
trailing_span = trailing_span.to(self.token.span);
509+
self.bump();
510+
}
511+
if self.token.kind == token::OpenDelim(token::Paren) {
512+
// Recover from bad turbofish: `foo.collect::Vec<_>()`.
513+
let args = AngleBracketedArgs { args, span }.into();
514+
segment.args = args;
515+
516+
self.struct_span_err(
517+
span,
518+
"generic parameters without surrounding angle brackets",
519+
)
520+
.multipart_suggestion(
521+
"surround the type parameters with angle brackets",
522+
vec![
523+
(span.shrink_to_lo(), "<".to_string()),
524+
(trailing_span, ">".to_string()),
525+
],
526+
Applicability::MachineApplicable,
527+
)
528+
.emit();
529+
} else {
530+
// This doesn't look like an invalid turbofish, can't recover parse state.
531+
*self = snapshot;
532+
}
533+
}
534+
Err(mut err) => {
535+
// We could't parse generic parameters, unlikely to be a turbofish. Rely on
536+
// generic parse error instead.
537+
err.cancel();
538+
*self = snapshot;
539+
}
540+
}
541+
}
542+
}
543+
491544
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
492545
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
493546
/// 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,10 @@
1+
fn main() {
2+
let _ = vec![1, 2, 3].into_iter().collect::Vec<_>();
3+
//~^ ERROR generic parameters without surrounding angle brackets
4+
let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>>();
5+
//~^ ERROR generic parameters without surrounding angle brackets
6+
let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>();
7+
//~^ ERROR generic parameters without surrounding angle brackets
8+
let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>();
9+
//~^ ERROR generic parameters without surrounding angle brackets
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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: generic parameters without surrounding angle brackets
13+
--> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:4:48
14+
|
15+
LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>>();
16+
| ^^^^^^
17+
|
18+
help: surround the type parameters with angle brackets
19+
|
20+
LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
21+
| ^ ^
22+
23+
error: generic parameters without surrounding angle brackets
24+
--> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:6:48
25+
|
26+
LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>();
27+
| ^^^^^^
28+
|
29+
help: surround the type parameters with angle brackets
30+
|
31+
LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
32+
| ^ ^
33+
34+
error: generic parameters without surrounding angle brackets
35+
--> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:8:48
36+
|
37+
LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>();
38+
| ^^^^^^
39+
|
40+
help: surround the type parameters with angle brackets
41+
|
42+
LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
43+
| ^ ^
44+
45+
error: aborting due to 4 previous errors
46+

0 commit comments

Comments
 (0)