1
Fork 0

Auto merge of #80065 - b-naber:parse-angle-arg-diagnostics, r=petrochenkov

Improve diagnostics when parsing angle args

https://github.com/rust-lang/rust/pull/79266 introduced parsing of generic arguments in associated type constraints, this however resulted in possibly very confusing error messages in cases in which closing angle brackets were missing such as in `Vec<(u32, _, _) = vec![]`, which outputs an incorrectly parsed equality constraint error, as noted by `@cynecx.`

This PR tries to provide better error messages in such cases.

r? `@petrochenkov`
This commit is contained in:
bors 2021-01-23 06:27:21 +00:00
commit 1986b58c64
17 changed files with 169 additions and 88 deletions

View file

@ -2,14 +2,13 @@ use super::ty::AllowPlus;
use super::TokenType; use super::TokenType;
use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType}; use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
use rustc_ast as ast;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Lit, LitKind, TokenKind}; use rustc_ast::token::{self, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp; use rustc_ast::util::parser::AssocOp;
use rustc_ast::{ use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat, use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
PatKind, Path, PathSegment, QSelf, Ty, TyKind,
};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err}; use rustc_errors::{pluralize, struct_span_err};
@ -220,6 +219,7 @@ impl<'a> Parser<'a> {
edible: &[TokenKind], edible: &[TokenKind],
inedible: &[TokenKind], inedible: &[TokenKind],
) -> PResult<'a, bool /* recovered */> { ) -> PResult<'a, bool /* recovered */> {
debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
fn tokens_to_string(tokens: &[TokenType]) -> String { fn tokens_to_string(tokens: &[TokenType]) -> String {
let mut i = tokens.iter(); let mut i = tokens.iter();
// This might be a sign we need a connect method on `Iterator`. // This might be a sign we need a connect method on `Iterator`.
@ -245,6 +245,7 @@ impl<'a> Parser<'a> {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
expected.sort_by_cached_key(|x| x.to_string()); expected.sort_by_cached_key(|x| x.to_string());
expected.dedup(); expected.dedup();
let expect = tokens_to_string(&expected[..]); let expect = tokens_to_string(&expected[..]);
let actual = super::token_descr(&self.token); let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@ -270,6 +271,16 @@ impl<'a> Parser<'a> {
}; };
self.last_unexpected_token_span = Some(self.token.span); self.last_unexpected_token_span = Some(self.token.span);
let mut err = self.struct_span_err(self.token.span, &msg_exp); let mut err = self.struct_span_err(self.token.span, &msg_exp);
// Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens
// there are unclosed angle brackets
if self.unmatched_angle_bracket_count > 0
&& self.token.kind == TokenKind::Eq
&& expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Gt)))
{
err.span_label(self.prev_token.span, "maybe try to close unmatched angle bracket");
}
let sp = if self.token == token::Eof { let sp = if self.token == token::Eof {
// This is EOF; don't want to point at the following char, but rather the last token. // This is EOF; don't want to point at the following char, but rather the last token.
self.prev_token.span self.prev_token.span

View file

@ -277,7 +277,7 @@ impl TokenCursor {
} }
} }
#[derive(Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
enum TokenType { enum TokenType {
Token(TokenKind), Token(TokenKind),
Keyword(Symbol), Keyword(Symbol),

View file

@ -185,7 +185,6 @@ impl<'a> Parser<'a> {
pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> { pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
let ident = self.parse_path_segment_ident()?; let ident = self.parse_path_segment_ident()?;
let is_args_start = |token: &Token| { let is_args_start = |token: &Token| {
matches!( matches!(
token.kind, token.kind,
@ -420,7 +419,10 @@ impl<'a> Parser<'a> {
match arg { match arg {
Some(arg) => { Some(arg) => {
if self.check(&token::Colon) | self.check(&token::Eq) { if self.check(&token::Colon) | self.check(&token::Eq) {
let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?; let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) {
Ok(ident_gen_args) => ident_gen_args,
Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))),
};
let kind = if self.eat(&token::Colon) { let kind = if self.eat(&token::Colon) {
// Parse associated type constraint bound. // Parse associated type constraint bound.
@ -561,50 +563,15 @@ impl<'a> Parser<'a> {
fn get_ident_from_generic_arg( fn get_ident_from_generic_arg(
&self, &self,
gen_arg: GenericArg, gen_arg: GenericArg,
lo: Span, ) -> Result<(Ident, Option<GenericArgs>), GenericArg> {
) -> PResult<'a, (Ident, Option<GenericArgs>)> { if let GenericArg::Type(ty) = &gen_arg {
let gen_arg_span = gen_arg.span(); if let ast::TyKind::Path(qself, path) = &ty.kind {
match gen_arg { if qself.is_none() && path.segments.len() == 1 {
GenericArg::Type(t) => match t.into_inner().kind { let seg = &path.segments[0];
ast::TyKind::Path(qself, mut path) => { return Ok((seg.ident, seg.args.as_deref().cloned()));
if let Some(qself) = qself {
let mut err = self.struct_span_err(
gen_arg_span,
"qualified paths cannot be used in associated type constraints",
);
err.span_label(
qself.path_span,
"not allowed in associated type constraints",
);
return Err(err);
}
if path.segments.len() == 1 {
let path_seg = path.segments.remove(0);
let ident = path_seg.ident;
let gen_args = path_seg.args.map(|args| args.into_inner());
return Ok((ident, gen_args));
}
let err = self.struct_span_err(
path.span,
"paths with multiple segments cannot be used in associated type constraints",
);
return Err(err);
}
_ => {
let span = lo.to(self.prev_token.span);
let err = self.struct_span_err(
span,
"only path types can be used in associated type constraints",
);
return Err(err);
}
},
_ => {
let span = lo.to(self.prev_token.span);
let err = self
.struct_span_err(span, "only types can be used in associated type constraints");
return Err(err);
} }
} }
} }
Err(gen_arg)
}
} }

View file

@ -2,7 +2,9 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
--> $DIR/trait-path-expected-token.rs:8:33 --> $DIR/trait-path-expected-token.rs:8:33
| |
LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {} LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
| ^ expected one of 7 possible tokens | - ^ expected one of 7 possible tokens
| |
| maybe try to close unmatched angle bracket
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/trait-path-expected-token.rs:1:12 --> $DIR/trait-path-expected-token.rs:1:12

View file

@ -17,7 +17,7 @@ mod error2 {
} }
fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {} fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
//~^ ERROR: only types can be used in associated type constraints //~^ ERROR: expected one of
} }
fn main() {} fn main() {}

View file

@ -6,11 +6,13 @@ LL | fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
| | | |
| while parsing a const generic argument starting here | while parsing a const generic argument starting here
error: only types can be used in associated type constraints error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/trait-path-expressions.rs:19:30 --> $DIR/trait-path-expressions.rs:19:36
| |
LL | fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {} LL | fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
| ^^^^^ | - ^ expected one of `,`, `:`, or `>`
| |
| maybe try to close unmatched angle bracket
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/trait-path-expressions.rs:1:12 --> $DIR/trait-path-expressions.rs:1:12

View file

@ -28,7 +28,9 @@ error: expected one of `>`, a const expression, lifetime, or type, found `=`
--> $DIR/trait-path-missing-gen_arg.rs:17:30 --> $DIR/trait-path-missing-gen_arg.rs:17:30
| |
LL | fn f1<'a>(arg : Box<dyn X< = 32 >>) {} LL | fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
| ^ expected one of `>`, a const expression, lifetime, or type | - ^ expected one of `>`, a const expression, lifetime, or type
| |
| maybe try to close unmatched angle bracket
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/trait-path-missing-gen_arg.rs:1:12 --> $DIR/trait-path-missing-gen_arg.rs:1:12

View file

@ -7,7 +7,7 @@ const _: () = {
} }
fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {} fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
//~^ ERROR: paths with multiple segments cannot be used in associated type constraints //~^ ERROR: expected one of
}; };
const _: () = { const _: () = {
@ -18,7 +18,7 @@ const _: () = {
trait Z {} trait Z {}
impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {} impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
//~^ ERROR: qualified paths cannot be used in associated type constraints //~^ ERROR: expected one of
}; };
const _: () = { const _: () = {
@ -29,7 +29,7 @@ const _: () = {
trait Z {} trait Z {}
impl<T : X<X::Y<'a> = &'a u32>> Z for T {} impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
//~^ ERROR: paths with multiple segments cannot be used in associated type constraints //~^ ERROR: expected one of
}; };
fn main() {} fn main() {}

View file

@ -1,22 +1,26 @@
error: paths with multiple segments cannot be used in associated type constraints error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, or `>`, found `=`
--> $DIR/trait-path-segments.rs:9:31 --> $DIR/trait-path-segments.rs:9:36
| |
LL | fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {} LL | fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
| ^^^^ | - ^ expected one of 8 possible tokens
| |
| maybe try to close unmatched angle bracket
error: qualified paths cannot be used in associated type constraints error: expected one of `,`, `::`, `:`, or `>`, found `=`
--> $DIR/trait-path-segments.rs:20:16 --> $DIR/trait-path-segments.rs:20:35
| |
LL | impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {} LL | impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
| ^^^^^^^^^-^^^^^^^^ | - ^ expected one of `,`, `::`, `:`, or `>`
| | | |
| not allowed in associated type constraints | maybe try to close unmatched angle bracket
error: paths with multiple segments cannot be used in associated type constraints error: expected one of `!`, `+`, `,`, `::`, `:`, or `>`, found `=`
--> $DIR/trait-path-segments.rs:31:16 --> $DIR/trait-path-segments.rs:31:25
| |
LL | impl<T : X<X::Y<'a> = &'a u32>> Z for T {} LL | impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
| ^^^^^^^^ | - ^ expected one of `!`, `+`, `,`, `::`, `:`, or `>`
| |
| maybe try to close unmatched angle bracket
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/trait-path-segments.rs:1:12 --> $DIR/trait-path-segments.rs:1:12

View file

@ -7,17 +7,17 @@ trait X {
const _: () = { const _: () = {
fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {} fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
//~^ ERROR: only path types can be used in associated type constraints //~^ ERROR: expected one of
}; };
const _: () = { const _: () = {
fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
//~^ ERROR: only path types can be used in associated type constraints //~^ ERROR: expected one of
}; };
const _: () = { const _: () = {
fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {} fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
//~^ ERROR: only types can be used in associated type constraints //~^ ERROR: expected one of
}; };
fn main() {} fn main() {}

View file

@ -1,20 +1,26 @@
error: only path types can be used in associated type constraints error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/trait-path-types.rs:9:29 --> $DIR/trait-path-types.rs:9:37
| |
LL | fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {} LL | fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
| ^^^^^^^ | - ^ expected one of `,`, `:`, or `>`
| |
| maybe try to close unmatched angle bracket
error: only path types can be used in associated type constraints error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/trait-path-types.rs:14:29 --> $DIR/trait-path-types.rs:14:37
| |
LL | fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {} LL | fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
| ^^^^^^^ | - ^ expected one of `,`, `:`, or `>`
| |
| maybe try to close unmatched angle bracket
error: only types can be used in associated type constraints error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/trait-path-types.rs:19:30 --> $DIR/trait-path-types.rs:19:33
| |
LL | fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {} LL | fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
| ^^ | -- ^ expected one of `,`, `:`, or `>`
| |
| maybe try to close unmatched angle bracket
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/trait-path-types.rs:1:12 --> $DIR/trait-path-types.rs:1:12

View file

@ -1,6 +1,8 @@
fn main () { fn main () {
let sr: Vec<(u32, _, _) = vec![]; let sr: Vec<(u32, _, _) = vec![];
//~^ ERROR only path types can be used in associated type constraints //~^ ERROR expected one of
let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
//~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built //~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built
} }

View file

@ -1,13 +1,14 @@
error: only path types can be used in associated type constraints error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/issue-34334.rs:2:17 --> $DIR/issue-34334.rs:2:29
| |
LL | let sr: Vec<(u32, _, _) = vec![]; LL | let sr: Vec<(u32, _, _) = vec![];
| -- ^^^^^^^^^^^ | -- - ^ expected one of `,`, `:`, or `>`
| | | | |
| | maybe try to close unmatched angle bracket
| while parsing the type for `sr` | while parsing the type for `sr`
error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()` error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()`
--> $DIR/issue-34334.rs:4:87 --> $DIR/issue-34334.rs:5:87
| |
LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
| ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>` | ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`

View file

@ -0,0 +1,23 @@
struct Foo<T1, T2> {
_a : T1,
_b : T2,
}
fn test1<T>(arg : T) {
let v : Vec<(u32,_) = vec![];
//~^ ERROR: expected one of
//~| ERROR: type annotations needed
}
fn test2<T1, T2>(arg1 : T1, arg2 : T2) {
let foo : Foo::<T1, T2 = Foo {_a : arg1, _b : arg2};
//~^ ERROR: expected one of
}
fn test3<'a>(arg : &'a u32) {
let v : Vec<'a = vec![];
//~^ ERROR: expected one of
//~| ERROR: type annotations needed for `Vec<T>`
}
fn main() {}

View file

@ -0,0 +1,49 @@
error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:23
|
LL | let v : Vec<(u32,_) = vec![];
| - - ^ expected one of `,`, `:`, or `>`
| | |
| | maybe try to close unmatched angle bracket
| while parsing the type for `v`
error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `{`
--> $DIR/missing-closing-angle-bracket-eq-constraint.rs:13:32
|
LL | let foo : Foo::<T1, T2 = Foo {_a : arg1, _b : arg2};
| --- ^ expected one of 7 possible tokens
| |
| while parsing the type for `foo`
error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:18
|
LL | let v : Vec<'a = vec![];
| - -- ^ expected one of `,`, `:`, or `>`
| | |
| | maybe try to close unmatched angle bracket
| while parsing the type for `v`
error[E0282]: type annotations needed for `Vec<T>`
--> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:25
|
LL | let v : Vec<(u32,_) = vec![];
| - ^^^^^^ cannot infer type for type parameter `T`
| |
| consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0282]: type annotations needed for `Vec<T>`
--> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:20
|
LL | let v : Vec<'a = vec![];
| - ^^^^^^ cannot infer type for type parameter `T`
| |
| consider giving `v` the explicit type `Vec<T>`, where the type parameter `T` is specified
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0282`.

View file

@ -0,0 +1,4 @@
fn main() {
let v : Vec::<Vec<(u32,_,_)> = vec![vec![]];
//~^ ERROR: expected one of
}

View file

@ -0,0 +1,8 @@
error: expected one of `,` or `>`, found `;`
--> $DIR/nested-missing-closing-angle-bracket.rs:2:46
|
LL | let v : Vec::<Vec<(u32,_,_)> = vec![vec![]];
| - while parsing the type for `v` ^ expected one of `,` or `>`
error: aborting due to previous error