Skip to content

Commit fae7bc7

Browse files
authored
Rollup merge of rust-lang#64192 - estebank:turbofish-madness, r=petrochenkov
Bail out when encountering likely missing turbofish in parser When encountering a likely intended turbofish without `::`, bubble up the diagnostic instead of emitting it to allow the parser to recover more gracefully and avoid uneccessary type errors that are likely to be wrong. Fix rust-lang#61329.
2 parents da61325 + dc613c6 commit fae7bc7

9 files changed

+37
-138
lines changed

src/libsyntax/parse/diagnostics.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ impl<'a> Parser<'a> {
544544
/// Produce an error if comparison operators are chained (RFC #558).
545545
/// We only need to check lhs, not rhs, because all comparison ops
546546
/// have same precedence and are left-associative
547-
crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) {
547+
crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) -> PResult<'a, ()> {
548548
debug_assert!(outer_op.is_comparison(),
549549
"check_no_chained_comparison: {:?} is not comparison",
550550
outer_op);
@@ -563,11 +563,14 @@ impl<'a> Parser<'a> {
563563
err.help(
564564
"use `::<...>` instead of `<...>` if you meant to specify type arguments");
565565
err.help("or use `(...)` if you meant to specify fn arguments");
566+
// These cases cause too many knock-down errors, bail out (#61329).
567+
return Err(err);
566568
}
567569
err.emit();
568570
}
569571
_ => {}
570572
}
573+
Ok(())
571574
}
572575

573576
crate fn maybe_report_ambiguous_plus(

src/libsyntax/parse/parser/expr.rs

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

232232
self.bump();
233233
if op.is_comparison() {
234-
self.check_no_chained_comparison(&lhs, &op);
234+
self.check_no_chained_comparison(&lhs, &op)?;
235235
}
236236
// Special cases:
237237
if op == AssocOp::As {

src/test/ui-fulldeps/pprust-expr-roundtrip.rs

+25-22
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ use syntax::print::pprust;
3232
use syntax::ptr::P;
3333

3434

35-
fn parse_expr(ps: &ParseSess, src: &str) -> P<Expr> {
35+
fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> {
3636
let src_as_string = src.to_string();
3737

38-
let mut p = parse::new_parser_from_source_str(ps,
39-
FileName::Custom(src_as_string.clone()),
40-
src_as_string);
41-
p.parse_expr().unwrap()
38+
let mut p = parse::new_parser_from_source_str(
39+
ps,
40+
FileName::Custom(src_as_string.clone()),
41+
src_as_string,
42+
);
43+
p.parse_expr().map_err(|mut e| e.cancel()).ok()
4244
}
4345

4446

@@ -209,22 +211,23 @@ fn run() {
209211
let printed = pprust::expr_to_string(&e);
210212
println!("printed: {}", printed);
211213

212-
let mut parsed = parse_expr(&ps, &printed);
213-
214-
// We want to know if `parsed` is structurally identical to `e`, ignoring trivial
215-
// differences like placement of `Paren`s or the exact ranges of node spans.
216-
// Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s
217-
// everywhere we can, then pretty-print. This should give an unambiguous representation of
218-
// each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't
219-
// relying on the correctness of the very thing we're testing.
220-
RemoveParens.visit_expr(&mut e);
221-
AddParens.visit_expr(&mut e);
222-
let text1 = pprust::expr_to_string(&e);
223-
RemoveParens.visit_expr(&mut parsed);
224-
AddParens.visit_expr(&mut parsed);
225-
let text2 = pprust::expr_to_string(&parsed);
226-
assert!(text1 == text2,
227-
"exprs are not equal:\n e = {:?}\n parsed = {:?}",
228-
text1, text2);
214+
// Ignore expressions with chained comparisons that fail to parse
215+
if let Some(mut parsed) = parse_expr(&ps, &printed) {
216+
// We want to know if `parsed` is structurally identical to `e`, ignoring trivial
217+
// differences like placement of `Paren`s or the exact ranges of node spans.
218+
// Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s
219+
// everywhere we can, then pretty-print. This should give an unambiguous representation
220+
// of each `Expr`, and it bypasses nearly all of the parenthesization logic, so we
221+
// aren't relying on the correctness of the very thing we're testing.
222+
RemoveParens.visit_expr(&mut e);
223+
AddParens.visit_expr(&mut e);
224+
let text1 = pprust::expr_to_string(&e);
225+
RemoveParens.visit_expr(&mut parsed);
226+
AddParens.visit_expr(&mut parsed);
227+
let text2 = pprust::expr_to_string(&parsed);
228+
assert!(text1 == text2,
229+
"exprs are not equal:\n e = {:?}\n parsed = {:?}",
230+
text1, text2);
231+
}
229232
});
230233
}
-11
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,16 @@
11
fn foo() {
22
(0..13).collect<Vec<i32>>();
33
//~^ ERROR chained comparison
4-
//~| ERROR expected value, found struct `Vec`
5-
//~| ERROR expected value, found builtin type `i32`
6-
//~| ERROR attempted to take value of method `collect`
74
}
85

96
fn bar() {
107
Vec<i32>::new();
118
//~^ ERROR chained comparison
12-
//~| ERROR expected value, found struct `Vec`
13-
//~| ERROR expected value, found builtin type `i32`
14-
//~| ERROR cannot find function `new` in the crate root
159
}
1610

1711
fn qux() {
1812
(0..13).collect<Vec<i32>();
1913
//~^ ERROR chained comparison
20-
//~| ERROR chained comparison
21-
//~| ERROR expected value, found struct `Vec`
22-
//~| ERROR expected value, found builtin type `i32`
23-
//~| ERROR attempted to take value of method `collect`
24-
//~| ERROR mismatched types
2514
}
2615

2716
fn main() {}

src/test/ui/did_you_mean/issue-40396.stderr

+3-77
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | (0..13).collect<Vec<i32>>();
88
= help: or use `(...)` if you meant to specify fn arguments
99

1010
error: chained comparison operators require parentheses
11-
--> $DIR/issue-40396.rs:10:8
11+
--> $DIR/issue-40396.rs:7:8
1212
|
1313
LL | Vec<i32>::new();
1414
| ^^^^^^^
@@ -17,87 +17,13 @@ LL | Vec<i32>::new();
1717
= help: or use `(...)` if you meant to specify fn arguments
1818

1919
error: chained comparison operators require parentheses
20-
--> $DIR/issue-40396.rs:18:20
20+
--> $DIR/issue-40396.rs:12:20
2121
|
2222
LL | (0..13).collect<Vec<i32>();
2323
| ^^^^^^^^
2424
|
2525
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
2626
= help: or use `(...)` if you meant to specify fn arguments
2727

28-
error: chained comparison operators require parentheses
29-
--> $DIR/issue-40396.rs:18:24
30-
|
31-
LL | (0..13).collect<Vec<i32>();
32-
| ^^^^^^
33-
|
34-
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
35-
= help: or use `(...)` if you meant to specify fn arguments
36-
37-
error[E0423]: expected value, found struct `Vec`
38-
--> $DIR/issue-40396.rs:2:21
39-
|
40-
LL | (0..13).collect<Vec<i32>>();
41-
| ^^^ did you mean `Vec { /* fields */ }`?
42-
43-
error[E0423]: expected value, found builtin type `i32`
44-
--> $DIR/issue-40396.rs:2:25
45-
|
46-
LL | (0..13).collect<Vec<i32>>();
47-
| ^^^ not a value
48-
49-
error[E0423]: expected value, found struct `Vec`
50-
--> $DIR/issue-40396.rs:10:5
51-
|
52-
LL | Vec<i32>::new();
53-
| ^^^ did you mean `Vec { /* fields */ }`?
54-
55-
error[E0423]: expected value, found builtin type `i32`
56-
--> $DIR/issue-40396.rs:10:9
57-
|
58-
LL | Vec<i32>::new();
59-
| ^^^ not a value
60-
61-
error[E0425]: cannot find function `new` in the crate root
62-
--> $DIR/issue-40396.rs:10:15
63-
|
64-
LL | Vec<i32>::new();
65-
| ^^^ not found in the crate root
66-
67-
error[E0423]: expected value, found struct `Vec`
68-
--> $DIR/issue-40396.rs:18:21
69-
|
70-
LL | (0..13).collect<Vec<i32>();
71-
| ^^^ did you mean `Vec { /* fields */ }`?
72-
73-
error[E0423]: expected value, found builtin type `i32`
74-
--> $DIR/issue-40396.rs:18:25
75-
|
76-
LL | (0..13).collect<Vec<i32>();
77-
| ^^^ not a value
78-
79-
error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
80-
--> $DIR/issue-40396.rs:2:13
81-
|
82-
LL | (0..13).collect<Vec<i32>>();
83-
| ^^^^^^^ help: use parentheses to call the method: `collect()`
84-
85-
error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
86-
--> $DIR/issue-40396.rs:18:13
87-
|
88-
LL | (0..13).collect<Vec<i32>();
89-
| ^^^^^^^ help: use parentheses to call the method: `collect()`
90-
91-
error[E0308]: mismatched types
92-
--> $DIR/issue-40396.rs:18:29
93-
|
94-
LL | (0..13).collect<Vec<i32>();
95-
| ^^ expected bool, found ()
96-
|
97-
= note: expected type `bool`
98-
found type `()`
99-
100-
error: aborting due to 14 previous errors
28+
error: aborting due to 3 previous errors
10129

102-
Some errors have detailed explanations: E0308, E0423, E0425, E0615.
103-
For more information about an error, try `rustc --explain E0308`.

src/test/ui/parser/require-parens-for-chained-comparison.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ fn main() {
1111
//~| ERROR: mismatched types
1212

1313
f<X>();
14-
//~^ ERROR: chained comparison operators require parentheses
15-
//~| ERROR: binary operation `<` cannot be applied to type `fn() {f::<_>}`
14+
//~^ ERROR chained comparison operators require parentheses
1615
//~| HELP: use `::<...>` instead of `<...>`
1716
//~| HELP: or use `(...)`
1817
}

src/test/ui/parser/require-parens-for-chained-comparison.stderr

+2-13
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,6 @@ LL | false == 0 < 2;
3737
= note: expected type `bool`
3838
found type `{integer}`
3939

40-
error[E0369]: binary operation `<` cannot be applied to type `fn() {f::<_>}`
41-
--> $DIR/require-parens-for-chained-comparison.rs:13:6
42-
|
43-
LL | f<X>();
44-
| -^- X
45-
| |
46-
| fn() {f::<_>}
47-
|
48-
= note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() {f::<_>}`
49-
50-
error: aborting due to 6 previous errors
40+
error: aborting due to 5 previous errors
5141

52-
Some errors have detailed explanations: E0308, E0369.
53-
For more information about an error, try `rustc --explain E0308`.
42+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/parser/trait-object-lifetime-parens.rs

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ fn check<'a>() {
99
let _: Box<('a) + Trait>;
1010
//~^ ERROR expected type, found `'a`
1111
//~| ERROR expected `:`, found `)`
12-
//~| ERROR chained comparison operators require parentheses
1312
}
1413

1514
fn main() {}

src/test/ui/parser/trait-object-lifetime-parens.stderr

+1-10
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,6 @@ error: expected `:`, found `)`
1616
LL | let _: Box<('a) + Trait>;
1717
| ^ expected `:`
1818

19-
error: chained comparison operators require parentheses
20-
--> $DIR/trait-object-lifetime-parens.rs:9:15
21-
|
22-
LL | let _: Box<('a) + Trait>;
23-
| ^^^^^^^^^^^^^^^
24-
|
25-
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
26-
= help: or use `(...)` if you meant to specify fn arguments
27-
2819
error: expected type, found `'a`
2920
--> $DIR/trait-object-lifetime-parens.rs:9:17
3021
|
@@ -33,5 +24,5 @@ LL | let _: Box<('a) + Trait>;
3324
| |
3425
| while parsing the type for `_`
3526

36-
error: aborting due to 5 previous errors
27+
error: aborting due to 4 previous errors
3728

0 commit comments

Comments
 (0)