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:
commit
fae7bc756e
9 changed files with 37 additions and 138 deletions
|
@ -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(
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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`.
|
|
||||||
|
|
|
@ -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 `(...)`
|
||||||
}
|
}
|
||||||
|
|
|
@ -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`.
|
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue