1
Fork 0

Rollup merge of #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 #61329.
This commit is contained in:
Mazdak Farrokhzad 2019-09-07 08:06:09 +02:00 committed by GitHub
commit fae7bc756e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 37 additions and 138 deletions

View file

@ -544,7 +544,7 @@ impl<'a> Parser<'a> {
/// Produce an error if comparison operators are chained (RFC #558). /// Produce an error if comparison operators are chained (RFC #558).
/// We only need to check lhs, not rhs, because all comparison ops /// We only need to check lhs, not rhs, because all comparison ops
/// have same precedence and are left-associative /// have same precedence and are left-associative
crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) { crate fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) -> PResult<'a, ()> {
debug_assert!(outer_op.is_comparison(), debug_assert!(outer_op.is_comparison(),
"check_no_chained_comparison: {:?} is not comparison", "check_no_chained_comparison: {:?} is not comparison",
outer_op); outer_op);
@ -563,11 +563,14 @@ impl<'a> Parser<'a> {
err.help( err.help(
"use `::<...>` instead of `<...>` if you meant to specify type arguments"); "use `::<...>` instead of `<...>` if you meant to specify type arguments");
err.help("or use `(...)` if you meant to specify fn arguments"); err.help("or use `(...)` if you meant to specify fn arguments");
// These cases cause too many knock-down errors, bail out (#61329).
return Err(err);
} }
err.emit(); err.emit();
} }
_ => {} _ => {}
} }
Ok(())
} }
crate fn maybe_report_ambiguous_plus( crate fn maybe_report_ambiguous_plus(

View file

@ -231,7 +231,7 @@ impl<'a> Parser<'a> {
self.bump(); self.bump();
if op.is_comparison() { if op.is_comparison() {
self.check_no_chained_comparison(&lhs, &op); self.check_no_chained_comparison(&lhs, &op)?;
} }
// Special cases: // Special cases:
if op == AssocOp::As { if op == AssocOp::As {

View file

@ -32,13 +32,15 @@ use syntax::print::pprust;
use syntax::ptr::P; use syntax::ptr::P;
fn parse_expr(ps: &ParseSess, src: &str) -> P<Expr> { fn parse_expr(ps: &ParseSess, src: &str) -> Option<P<Expr>> {
let src_as_string = src.to_string(); let src_as_string = src.to_string();
let mut p = parse::new_parser_from_source_str(ps, let mut p = parse::new_parser_from_source_str(
ps,
FileName::Custom(src_as_string.clone()), FileName::Custom(src_as_string.clone()),
src_as_string); src_as_string,
p.parse_expr().unwrap() );
p.parse_expr().map_err(|mut e| e.cancel()).ok()
} }
@ -209,14 +211,14 @@ fn run() {
let printed = pprust::expr_to_string(&e); let printed = pprust::expr_to_string(&e);
println!("printed: {}", printed); println!("printed: {}", printed);
let mut parsed = parse_expr(&ps, &printed); // Ignore expressions with chained comparisons that fail to parse
if let Some(mut parsed) = parse_expr(&ps, &printed) {
// We want to know if `parsed` is structurally identical to `e`, ignoring trivial // We want to know if `parsed` is structurally identical to `e`, ignoring trivial
// differences like placement of `Paren`s or the exact ranges of node spans. // differences like placement of `Paren`s or the exact ranges of node spans.
// Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s // Unfortunately, there is no easy way to make this comparison. Instead, we add `Paren`s
// everywhere we can, then pretty-print. This should give an unambiguous representation of // everywhere we can, then pretty-print. This should give an unambiguous representation
// each `Expr`, and it bypasses nearly all of the parenthesization logic, so we aren't // of each `Expr`, and it bypasses nearly all of the parenthesization logic, so we
// relying on the correctness of the very thing we're testing. // aren't relying on the correctness of the very thing we're testing.
RemoveParens.visit_expr(&mut e); RemoveParens.visit_expr(&mut e);
AddParens.visit_expr(&mut e); AddParens.visit_expr(&mut e);
let text1 = pprust::expr_to_string(&e); let text1 = pprust::expr_to_string(&e);
@ -226,5 +228,6 @@ fn run() {
assert!(text1 == text2, assert!(text1 == text2,
"exprs are not equal:\n e = {:?}\n parsed = {:?}", "exprs are not equal:\n e = {:?}\n parsed = {:?}",
text1, text2); text1, text2);
}
}); });
} }

View file

@ -1,27 +1,16 @@
fn foo() { fn foo() {
(0..13).collect<Vec<i32>>(); (0..13).collect<Vec<i32>>();
//~^ ERROR chained comparison //~^ ERROR chained comparison
//~| ERROR expected value, found struct `Vec`
//~| ERROR expected value, found builtin type `i32`
//~| ERROR attempted to take value of method `collect`
} }
fn bar() { fn bar() {
Vec<i32>::new(); Vec<i32>::new();
//~^ ERROR chained comparison //~^ ERROR chained comparison
//~| ERROR expected value, found struct `Vec`
//~| ERROR expected value, found builtin type `i32`
//~| ERROR cannot find function `new` in the crate root
} }
fn qux() { fn qux() {
(0..13).collect<Vec<i32>(); (0..13).collect<Vec<i32>();
//~^ ERROR chained comparison //~^ ERROR chained comparison
//~| ERROR chained comparison
//~| ERROR expected value, found struct `Vec`
//~| ERROR expected value, found builtin type `i32`
//~| ERROR attempted to take value of method `collect`
//~| ERROR mismatched types
} }
fn main() {} fn main() {}

View file

@ -8,7 +8,7 @@ LL | (0..13).collect<Vec<i32>>();
= help: or use `(...)` if you meant to specify fn arguments = help: or use `(...)` if you meant to specify fn arguments
error: chained comparison operators require parentheses error: chained comparison operators require parentheses
--> $DIR/issue-40396.rs:10:8 --> $DIR/issue-40396.rs:7:8
| |
LL | Vec<i32>::new(); LL | Vec<i32>::new();
| ^^^^^^^ | ^^^^^^^
@ -17,7 +17,7 @@ LL | Vec<i32>::new();
= help: or use `(...)` if you meant to specify fn arguments = help: or use `(...)` if you meant to specify fn arguments
error: chained comparison operators require parentheses error: chained comparison operators require parentheses
--> $DIR/issue-40396.rs:18:20 --> $DIR/issue-40396.rs:12:20
| |
LL | (0..13).collect<Vec<i32>(); LL | (0..13).collect<Vec<i32>();
| ^^^^^^^^ | ^^^^^^^^
@ -25,79 +25,5 @@ LL | (0..13).collect<Vec<i32>();
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
= help: or use `(...)` if you meant to specify fn arguments = help: or use `(...)` if you meant to specify fn arguments
error: chained comparison operators require parentheses error: aborting due to 3 previous errors
--> $DIR/issue-40396.rs:18:24
|
LL | (0..13).collect<Vec<i32>();
| ^^^^^^
|
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
= help: or use `(...)` if you meant to specify fn arguments
error[E0423]: expected value, found struct `Vec`
--> $DIR/issue-40396.rs:2:21
|
LL | (0..13).collect<Vec<i32>>();
| ^^^ did you mean `Vec { /* fields */ }`?
error[E0423]: expected value, found builtin type `i32`
--> $DIR/issue-40396.rs:2:25
|
LL | (0..13).collect<Vec<i32>>();
| ^^^ not a value
error[E0423]: expected value, found struct `Vec`
--> $DIR/issue-40396.rs:10:5
|
LL | Vec<i32>::new();
| ^^^ did you mean `Vec { /* fields */ }`?
error[E0423]: expected value, found builtin type `i32`
--> $DIR/issue-40396.rs:10:9
|
LL | Vec<i32>::new();
| ^^^ not a value
error[E0425]: cannot find function `new` in the crate root
--> $DIR/issue-40396.rs:10:15
|
LL | Vec<i32>::new();
| ^^^ not found in the crate root
error[E0423]: expected value, found struct `Vec`
--> $DIR/issue-40396.rs:18:21
|
LL | (0..13).collect<Vec<i32>();
| ^^^ did you mean `Vec { /* fields */ }`?
error[E0423]: expected value, found builtin type `i32`
--> $DIR/issue-40396.rs:18:25
|
LL | (0..13).collect<Vec<i32>();
| ^^^ not a value
error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
--> $DIR/issue-40396.rs:2:13
|
LL | (0..13).collect<Vec<i32>>();
| ^^^^^^^ help: use parentheses to call the method: `collect()`
error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
--> $DIR/issue-40396.rs:18:13
|
LL | (0..13).collect<Vec<i32>();
| ^^^^^^^ help: use parentheses to call the method: `collect()`
error[E0308]: mismatched types
--> $DIR/issue-40396.rs:18:29
|
LL | (0..13).collect<Vec<i32>();
| ^^ expected bool, found ()
|
= note: expected type `bool`
found type `()`
error: aborting due to 14 previous errors
Some errors have detailed explanations: E0308, E0423, E0425, E0615.
For more information about an error, try `rustc --explain E0308`.

View file

@ -11,8 +11,7 @@ fn main() {
//~| ERROR: mismatched types //~| ERROR: mismatched types
f<X>(); f<X>();
//~^ ERROR: chained comparison operators require parentheses //~^ ERROR chained comparison operators require parentheses
//~| ERROR: binary operation `<` cannot be applied to type `fn() {f::<_>}`
//~| HELP: use `::<...>` instead of `<...>` //~| HELP: use `::<...>` instead of `<...>`
//~| HELP: or use `(...)` //~| HELP: or use `(...)`
} }

View file

@ -37,17 +37,6 @@ LL | false == 0 < 2;
= note: expected type `bool` = note: expected type `bool`
found type `{integer}` found type `{integer}`
error[E0369]: binary operation `<` cannot be applied to type `fn() {f::<_>}` error: aborting due to 5 previous errors
--> $DIR/require-parens-for-chained-comparison.rs:13:6
|
LL | f<X>();
| -^- X
| |
| fn() {f::<_>}
|
= note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() {f::<_>}`
error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0308`.
Some errors have detailed explanations: E0308, E0369.
For more information about an error, try `rustc --explain E0308`.

View file

@ -9,7 +9,6 @@ fn check<'a>() {
let _: Box<('a) + Trait>; let _: Box<('a) + Trait>;
//~^ ERROR expected type, found `'a` //~^ ERROR expected type, found `'a`
//~| ERROR expected `:`, found `)` //~| ERROR expected `:`, found `)`
//~| ERROR chained comparison operators require parentheses
} }
fn main() {} fn main() {}

View file

@ -16,15 +16,6 @@ error: expected `:`, found `)`
LL | let _: Box<('a) + Trait>; LL | let _: Box<('a) + Trait>;
| ^ expected `:` | ^ expected `:`
error: chained comparison operators require parentheses
--> $DIR/trait-object-lifetime-parens.rs:9:15
|
LL | let _: Box<('a) + Trait>;
| ^^^^^^^^^^^^^^^
|
= help: use `::<...>` instead of `<...>` if you meant to specify type arguments
= help: or use `(...)` if you meant to specify fn arguments
error: expected type, found `'a` error: expected type, found `'a`
--> $DIR/trait-object-lifetime-parens.rs:9:17 --> $DIR/trait-object-lifetime-parens.rs:9:17
| |
@ -33,5 +24,5 @@ LL | let _: Box<('a) + Trait>;
| | | |
| while parsing the type for `_` | while parsing the type for `_`
error: aborting due to 5 previous errors error: aborting due to 4 previous errors