Skip to content

Commit 1986b58

Browse files
committed
Auto merge of rust-lang#80065 - b-naber:parse-angle-arg-diagnostics, r=petrochenkov
Improve diagnostics when parsing angle args rust-lang#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`
2 parents fe0fa59 + 3ba6cf1 commit 1986b58

17 files changed

+169
-88
lines changed

compiler/rustc_parse/src/parser/diagnostics.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ use super::ty::AllowPlus;
22
use super::TokenType;
33
use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
44

5+
use rustc_ast as ast;
56
use rustc_ast::ptr::P;
67
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
78
use rustc_ast::util::parser::AssocOp;
8-
use rustc_ast::{
9-
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
10-
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat,
11-
PatKind, Path, PathSegment, QSelf, Ty, TyKind,
12-
};
9+
use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
10+
use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
11+
use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
1312
use rustc_ast_pretty::pprust;
1413
use rustc_data_structures::fx::FxHashSet;
1514
use rustc_errors::{pluralize, struct_span_err};
@@ -220,6 +219,7 @@ impl<'a> Parser<'a> {
220219
edible: &[TokenKind],
221220
inedible: &[TokenKind],
222221
) -> PResult<'a, bool /* recovered */> {
222+
debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
223223
fn tokens_to_string(tokens: &[TokenType]) -> String {
224224
let mut i = tokens.iter();
225225
// This might be a sign we need a connect method on `Iterator`.
@@ -245,6 +245,7 @@ impl<'a> Parser<'a> {
245245
.collect::<Vec<_>>();
246246
expected.sort_by_cached_key(|x| x.to_string());
247247
expected.dedup();
248+
248249
let expect = tokens_to_string(&expected[..]);
249250
let actual = super::token_descr(&self.token);
250251
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@@ -270,6 +271,16 @@ impl<'a> Parser<'a> {
270271
};
271272
self.last_unexpected_token_span = Some(self.token.span);
272273
let mut err = self.struct_span_err(self.token.span, &msg_exp);
274+
275+
// Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens
276+
// there are unclosed angle brackets
277+
if self.unmatched_angle_bracket_count > 0
278+
&& self.token.kind == TokenKind::Eq
279+
&& expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Gt)))
280+
{
281+
err.span_label(self.prev_token.span, "maybe try to close unmatched angle bracket");
282+
}
283+
273284
let sp = if self.token == token::Eof {
274285
// This is EOF; don't want to point at the following char, but rather the last token.
275286
self.prev_token.span

compiler/rustc_parse/src/parser/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ impl TokenCursor {
277277
}
278278
}
279279

280-
#[derive(Clone, PartialEq)]
280+
#[derive(Debug, Clone, PartialEq)]
281281
enum TokenType {
282282
Token(TokenKind),
283283
Keyword(Symbol),

compiler/rustc_parse/src/parser/path.rs

+11-44
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ impl<'a> Parser<'a> {
185185

186186
pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
187187
let ident = self.parse_path_segment_ident()?;
188-
189188
let is_args_start = |token: &Token| {
190189
matches!(
191190
token.kind,
@@ -420,7 +419,10 @@ impl<'a> Parser<'a> {
420419
match arg {
421420
Some(arg) => {
422421
if self.check(&token::Colon) | self.check(&token::Eq) {
423-
let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?;
422+
let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) {
423+
Ok(ident_gen_args) => ident_gen_args,
424+
Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))),
425+
};
424426
let kind = if self.eat(&token::Colon) {
425427
// Parse associated type constraint bound.
426428

@@ -561,50 +563,15 @@ impl<'a> Parser<'a> {
561563
fn get_ident_from_generic_arg(
562564
&self,
563565
gen_arg: GenericArg,
564-
lo: Span,
565-
) -> PResult<'a, (Ident, Option<GenericArgs>)> {
566-
let gen_arg_span = gen_arg.span();
567-
match gen_arg {
568-
GenericArg::Type(t) => match t.into_inner().kind {
569-
ast::TyKind::Path(qself, mut path) => {
570-
if let Some(qself) = qself {
571-
let mut err = self.struct_span_err(
572-
gen_arg_span,
573-
"qualified paths cannot be used in associated type constraints",
574-
);
575-
err.span_label(
576-
qself.path_span,
577-
"not allowed in associated type constraints",
578-
);
579-
return Err(err);
580-
}
581-
if path.segments.len() == 1 {
582-
let path_seg = path.segments.remove(0);
583-
let ident = path_seg.ident;
584-
let gen_args = path_seg.args.map(|args| args.into_inner());
585-
return Ok((ident, gen_args));
586-
}
587-
let err = self.struct_span_err(
588-
path.span,
589-
"paths with multiple segments cannot be used in associated type constraints",
590-
);
591-
return Err(err);
592-
}
593-
_ => {
594-
let span = lo.to(self.prev_token.span);
595-
let err = self.struct_span_err(
596-
span,
597-
"only path types can be used in associated type constraints",
598-
);
599-
return Err(err);
566+
) -> Result<(Ident, Option<GenericArgs>), GenericArg> {
567+
if let GenericArg::Type(ty) = &gen_arg {
568+
if let ast::TyKind::Path(qself, path) = &ty.kind {
569+
if qself.is_none() && path.segments.len() == 1 {
570+
let seg = &path.segments[0];
571+
return Ok((seg.ident, seg.args.as_deref().cloned()));
600572
}
601-
},
602-
_ => {
603-
let span = lo.to(self.prev_token.span);
604-
let err = self
605-
.struct_span_err(span, "only types can be used in associated type constraints");
606-
return Err(err);
607573
}
608574
}
575+
Err(gen_arg)
609576
}
610577
}

src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
22
--> $DIR/trait-path-expected-token.rs:8:33
33
|
44
LL | fn f1<'a>(arg : Box<dyn X<Y = B = &'a ()>>) {}
5-
| ^ expected one of 7 possible tokens
5+
| - ^ expected one of 7 possible tokens
6+
| |
7+
| maybe try to close unmatched angle bracket
68

79
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
810
--> $DIR/trait-path-expected-token.rs:1:12

src/test/ui/generic-associated-types/parse/trait-path-expressions.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ mod error2 {
1717
}
1818

1919
fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
20-
//~^ ERROR: only types can be used in associated type constraints
20+
//~^ ERROR: expected one of
2121
}
2222

2323
fn main() {}

src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ LL | fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
66
| |
77
| while parsing a const generic argument starting here
88

9-
error: only types can be used in associated type constraints
10-
--> $DIR/trait-path-expressions.rs:19:30
9+
error: expected one of `,`, `:`, or `>`, found `=`
10+
--> $DIR/trait-path-expressions.rs:19:36
1111
|
1212
LL | fn f2<'a>(arg : Box<dyn X< { 1 } = 32 >>) {}
13-
| ^^^^^
13+
| - ^ expected one of `,`, `:`, or `>`
14+
| |
15+
| maybe try to close unmatched angle bracket
1416

1517
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
1618
--> $DIR/trait-path-expressions.rs:1:12

src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ error: expected one of `>`, a const expression, lifetime, or type, found `=`
2828
--> $DIR/trait-path-missing-gen_arg.rs:17:30
2929
|
3030
LL | fn f1<'a>(arg : Box<dyn X< = 32 >>) {}
31-
| ^ expected one of `>`, a const expression, lifetime, or type
31+
| - ^ expected one of `>`, a const expression, lifetime, or type
32+
| |
33+
| maybe try to close unmatched angle bracket
3234

3335
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
3436
--> $DIR/trait-path-missing-gen_arg.rs:1:12

src/test/ui/generic-associated-types/parse/trait-path-segments.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const _: () = {
77
}
88

99
fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
10-
//~^ ERROR: paths with multiple segments cannot be used in associated type constraints
10+
//~^ ERROR: expected one of
1111
};
1212

1313
const _: () = {
@@ -18,7 +18,7 @@ const _: () = {
1818
trait Z {}
1919

2020
impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
21-
//~^ ERROR: qualified paths cannot be used in associated type constraints
21+
//~^ ERROR: expected one of
2222
};
2323

2424
const _: () = {
@@ -29,7 +29,7 @@ const _: () = {
2929
trait Z {}
3030

3131
impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
32-
//~^ ERROR: paths with multiple segments cannot be used in associated type constraints
32+
//~^ ERROR: expected one of
3333
};
3434

3535
fn main() {}

src/test/ui/generic-associated-types/parse/trait-path-segments.stderr

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
1-
error: paths with multiple segments cannot be used in associated type constraints
2-
--> $DIR/trait-path-segments.rs:9:31
1+
error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, or `>`, found `=`
2+
--> $DIR/trait-path-segments.rs:9:36
33
|
44
LL | fn f1<'a>(arg : Box<dyn X<X::Y = u32>>) {}
5-
| ^^^^
5+
| - ^ expected one of 8 possible tokens
6+
| |
7+
| maybe try to close unmatched angle bracket
68

7-
error: qualified paths cannot be used in associated type constraints
8-
--> $DIR/trait-path-segments.rs:20:16
9+
error: expected one of `,`, `::`, `:`, or `>`, found `=`
10+
--> $DIR/trait-path-segments.rs:20:35
911
|
1012
LL | impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
11-
| ^^^^^^^^^-^^^^^^^^
12-
| |
13-
| not allowed in associated type constraints
13+
| - ^ expected one of `,`, `::`, `:`, or `>`
14+
| |
15+
| maybe try to close unmatched angle bracket
1416

15-
error: paths with multiple segments cannot be used in associated type constraints
16-
--> $DIR/trait-path-segments.rs:31:16
17+
error: expected one of `!`, `+`, `,`, `::`, `:`, or `>`, found `=`
18+
--> $DIR/trait-path-segments.rs:31:25
1719
|
1820
LL | impl<T : X<X::Y<'a> = &'a u32>> Z for T {}
19-
| ^^^^^^^^
21+
| - ^ expected one of `!`, `+`, `,`, `::`, `:`, or `>`
22+
| |
23+
| maybe try to close unmatched angle bracket
2024

2125
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
2226
--> $DIR/trait-path-segments.rs:1:12

src/test/ui/generic-associated-types/parse/trait-path-types.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ trait X {
77

88
const _: () = {
99
fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
10-
//~^ ERROR: only path types can be used in associated type constraints
10+
//~^ ERROR: expected one of
1111
};
1212

1313
const _: () = {
1414
fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
15-
//~^ ERROR: only path types can be used in associated type constraints
15+
//~^ ERROR: expected one of
1616
};
1717

1818
const _: () = {
1919
fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
20-
//~^ ERROR: only types can be used in associated type constraints
20+
//~^ ERROR: expected one of
2121
};
2222

2323
fn main() {}

src/test/ui/generic-associated-types/parse/trait-path-types.stderr

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
1-
error: only path types can be used in associated type constraints
2-
--> $DIR/trait-path-types.rs:9:29
1+
error: expected one of `,`, `:`, or `>`, found `=`
2+
--> $DIR/trait-path-types.rs:9:37
33
|
44
LL | fn f<'a>(arg : Box<dyn X< [u8; 1] = u32>>) {}
5-
| ^^^^^^^
5+
| - ^ expected one of `,`, `:`, or `>`
6+
| |
7+
| maybe try to close unmatched angle bracket
68

7-
error: only path types can be used in associated type constraints
8-
--> $DIR/trait-path-types.rs:14:29
9+
error: expected one of `,`, `:`, or `>`, found `=`
10+
--> $DIR/trait-path-types.rs:14:37
911
|
1012
LL | fn f1<'a>(arg : Box<dyn X<(Y<'a>) = &'a ()>>) {}
11-
| ^^^^^^^
13+
| - ^ expected one of `,`, `:`, or `>`
14+
| |
15+
| maybe try to close unmatched angle bracket
1216

13-
error: only types can be used in associated type constraints
14-
--> $DIR/trait-path-types.rs:19:30
17+
error: expected one of `,`, `:`, or `>`, found `=`
18+
--> $DIR/trait-path-types.rs:19:33
1519
|
1620
LL | fn f1<'a>(arg : Box<dyn X< 'a = u32 >>) {}
17-
| ^^
21+
| -- ^ expected one of `,`, `:`, or `>`
22+
| |
23+
| maybe try to close unmatched angle bracket
1824

1925
warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes
2026
--> $DIR/trait-path-types.rs:1:12

src/test/ui/issues/issue-34334.rs

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

src/test/ui/issues/issue-34334.stderr

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
error: only path types can be used in associated type constraints
2-
--> $DIR/issue-34334.rs:2:17
1+
error: expected one of `,`, `:`, or `>`, found `=`
2+
--> $DIR/issue-34334.rs:2:29
33
|
44
LL | let sr: Vec<(u32, _, _) = vec![];
5-
| -- ^^^^^^^^^^^
6-
| |
5+
| -- - ^ expected one of `,`, `:`, or `>`
6+
| | |
7+
| | maybe try to close unmatched angle bracket
78
| while parsing the type for `sr`
89

910
error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()`
10-
--> $DIR/issue-34334.rs:4:87
11+
--> $DIR/issue-34334.rs:5:87
1112
|
1213
LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
1314
| ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
struct Foo<T1, T2> {
2+
_a : T1,
3+
_b : T2,
4+
}
5+
6+
fn test1<T>(arg : T) {
7+
let v : Vec<(u32,_) = vec![];
8+
//~^ ERROR: expected one of
9+
//~| ERROR: type annotations needed
10+
}
11+
12+
fn test2<T1, T2>(arg1 : T1, arg2 : T2) {
13+
let foo : Foo::<T1, T2 = Foo {_a : arg1, _b : arg2};
14+
//~^ ERROR: expected one of
15+
}
16+
17+
fn test3<'a>(arg : &'a u32) {
18+
let v : Vec<'a = vec![];
19+
//~^ ERROR: expected one of
20+
//~| ERROR: type annotations needed for `Vec<T>`
21+
}
22+
23+
fn main() {}

0 commit comments

Comments
 (0)