Skip to content

Improve diagnostics when parsing angle args #80065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ use super::ty::AllowPlus;
use super::TokenType;
use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};

use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::{
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat,
PatKind, Path, PathSegment, QSelf, Ty, TyKind,
};
use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err};
Expand Down Expand Up @@ -220,6 +219,7 @@ impl<'a> Parser<'a> {
edible: &[TokenKind],
inedible: &[TokenKind],
) -> PResult<'a, bool /* recovered */> {
debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
fn tokens_to_string(tokens: &[TokenType]) -> String {
let mut i = tokens.iter();
// This might be a sign we need a connect method on `Iterator`.
Expand All @@ -245,6 +245,7 @@ impl<'a> Parser<'a> {
.collect::<Vec<_>>();
expected.sort_by_cached_key(|x| x.to_string());
expected.dedup();

let expect = tokens_to_string(&expected[..]);
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
Expand All @@ -270,6 +271,16 @@ impl<'a> Parser<'a> {
};
self.last_unexpected_token_span = Some(self.token.span);
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 {
// This is EOF; don't want to point at the following char, but rather the last token.
self.prev_token.span
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ impl TokenCursor {
}
}

#[derive(Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
enum TokenType {
Token(TokenKind),
Keyword(Symbol),
Expand Down
55 changes: 11 additions & 44 deletions compiler/rustc_parse/src/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ impl<'a> Parser<'a> {

pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
let ident = self.parse_path_segment_ident()?;

let is_args_start = |token: &Token| {
matches!(
token.kind,
Expand Down Expand Up @@ -420,7 +419,10 @@ impl<'a> Parser<'a> {
match arg {
Some(arg) => {
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) {
// Parse associated type constraint bound.

Expand Down Expand Up @@ -561,50 +563,15 @@ impl<'a> Parser<'a> {
fn get_ident_from_generic_arg(
&self,
gen_arg: GenericArg,
lo: Span,
) -> PResult<'a, (Ident, Option<GenericArgs>)> {
let gen_arg_span = gen_arg.span();
match gen_arg {
GenericArg::Type(t) => match t.into_inner().kind {
ast::TyKind::Path(qself, mut path) => {
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);
) -> Result<(Ident, Option<GenericArgs>), GenericArg> {
if let GenericArg::Type(ty) = &gen_arg {
if let ast::TyKind::Path(qself, path) = &ty.kind {
if qself.is_none() && path.segments.len() == 1 {
let seg = &path.segments[0];
return Ok((seg.ident, seg.args.as_deref().cloned()));
}
},
_ => {
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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=`
--> $DIR/trait-path-expected-token.rs:8:33
|
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
--> $DIR/trait-path-expected-token.rs:1:12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod error2 {
}

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() {}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ LL | fn f1<'a>(arg : Box<dyn X< 1 = 32 >>) {}
| |
| while parsing a const generic argument starting here

error: only types can be used in associated type constraints
--> $DIR/trait-path-expressions.rs:19:30
error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/trait-path-expressions.rs:19:36
|
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
--> $DIR/trait-path-expressions.rs:1:12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ error: expected one of `>`, a const expression, lifetime, or type, found `=`
--> $DIR/trait-path-missing-gen_arg.rs:17:30
|
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
--> $DIR/trait-path-missing-gen_arg.rs:1:12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const _: () = {
}

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 _: () = {
Expand All @@ -18,7 +18,7 @@ const _: () = {
trait Z {}

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 _: () = {
Expand All @@ -29,7 +29,7 @@ const _: () = {
trait Z {}

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() {}
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
error: paths with multiple segments cannot be used in associated type constraints
--> $DIR/trait-path-segments.rs:9:31
error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, or `>`, found `=`
--> $DIR/trait-path-segments.rs:9:36
|
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
--> $DIR/trait-path-segments.rs:20:16
error: expected one of `,`, `::`, `:`, or `>`, found `=`
--> $DIR/trait-path-segments.rs:20:35
|
LL | impl<T : X<<Self as X>::Y<'a> = &'a u32>> Z for T {}
| ^^^^^^^^^-^^^^^^^^
| |
| not allowed in associated type constraints
| - ^ expected one of `,`, `::`, `:`, or `>`
| |
| maybe try to close unmatched angle bracket

error: paths with multiple segments cannot be used in associated type constraints
--> $DIR/trait-path-segments.rs:31:16
error: expected one of `!`, `+`, `,`, `::`, `:`, or `>`, found `=`
--> $DIR/trait-path-segments.rs:31:25
|
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
--> $DIR/trait-path-segments.rs:1:12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ trait X {

const _: () = {
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 _: () = {
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 _: () = {
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() {}
24 changes: 15 additions & 9 deletions src/test/ui/generic-associated-types/parse/trait-path-types.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
error: only path types can be used in associated type constraints
--> $DIR/trait-path-types.rs:9:29
error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/trait-path-types.rs:9:37
|
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
--> $DIR/trait-path-types.rs:14:29
error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/trait-path-types.rs:14:37
|
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
--> $DIR/trait-path-types.rs:19:30
error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/trait-path-types.rs:19:33
|
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
--> $DIR/trait-path-types.rs:1:12
Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/issues/issue-34334.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
fn main () {
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();
//~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built

}
11 changes: 6 additions & 5 deletions src/test/ui/issues/issue-34334.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
error: only path types can be used in associated type constraints
--> $DIR/issue-34334.rs:2:17
error: expected one of `,`, `:`, or `>`, found `=`
--> $DIR/issue-34334.rs:2:29
|
LL | let sr: Vec<(u32, _, _) = vec![];
| -- ^^^^^^^^^^^
| |
| -- - ^ expected one of `,`, `:`, or `>`
| | |
| | maybe try to close unmatched angle bracket
| while parsing the type for `sr`

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();
| ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator<Item=()>`
Expand Down
23 changes: 23 additions & 0 deletions src/test/ui/parser/missing-closing-angle-bracket-eq-constraint.rs
Original file line number Diff line number Diff line change
@@ -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() {}
Loading