From 42aaa5fc7f14516150a290b0d39902aa40070d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 26 Apr 2019 19:15:01 -0700 Subject: [PATCH 1/2] Parse qualified paths in type params and provide custom diagnostic --- src/libsyntax/parse/parser.rs | 59 +++++++++++++++++--- src/test/ui/parser/qpath-in-type-args.rs | 11 ++++ src/test/ui/parser/qpath-in-type-args.stderr | 10 ++++ 3 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/parser/qpath-in-type-args.rs create mode 100644 src/test/ui/parser/qpath-in-type-args.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 75d687be28003..8b30c00edf258 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5834,12 +5834,11 @@ impl<'a> Parser<'a> { lifetimes } - /// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`. - fn parse_ty_param(&mut self, - preceding_attrs: Vec) - -> PResult<'a, GenericParam> { - let ident = self.parse_ident()?; - + fn parse_ty_param_inner( + &mut self, + preceding_attrs: Vec, + ident: ast::Ident, + ) -> PResult<'a, GenericParam> { // Parse optional colon and param bounds. let bounds = if self.eat(&token::Colon) { self.parse_generic_bounds(Some(self.prev_span))? @@ -5864,6 +5863,47 @@ impl<'a> Parser<'a> { }) } + /// Matches `typaram = IDENT (`?` unbound)? optbounds ( EQ ty )?`. + fn parse_ty_param( + &mut self, + preceding_attrs: Vec, + ) -> PResult<'a, GenericParam> { + let ident = self.parse_ident()?; + self.parse_ty_param_inner(preceding_attrs, ident) + } + + /// Parse an arbitrary path and suggest moving it to the `where` clause (#26271) + fn parse_bad_ty_param( + &mut self, + preceding_attrs: Vec, + ) -> PResult<'a, bool /* break */> { + let snapshot = self.clone(); + Ok(match self.parse_qpath(PathStyle::Type) + .and_then(|(_qpath, path)| self.parse_ty_param_inner( + preceding_attrs, + ast::Ident::from_str(&format!("{}", path)), + ).map(|_| path.span.to(self.prev_span))) + { // We discard the generated type param, we only want to confirm that it is otherwise + // well-formed. If it isn't, we revert back to normal behavior and emit a non-targeted + // parse error. If it *is*, we *don't* add to the type param list to avoid having + // spurious "unused type param" errors. + Ok(span) => { + self.struct_span_err( + span, + "qualified paths are not allowed in generic parameters", + ) + .note("move this constraint to the `where` clause") + .emit(); + false + } + Err(mut err) => { + err.cancel(); + mem::replace(self, snapshot); + true + } + }) + } + /// Parses the following grammar: /// /// TraitItemAssocTy = Ident ["<"...">"] [":" [GenericBounds]] ["where" ...] ["=" Ty] @@ -5934,13 +5974,18 @@ impl<'a> Parser<'a> { } else if self.check_ident() { // Parse type parameter. params.push(self.parse_ty_param(attrs)?); + } else if self.token == token::Lt { + self.bump() ; // `<` + if self.parse_bad_ty_param(attrs)? { + break + } } else { // Check for trailing attributes and stop parsing. if !attrs.is_empty() { if !params.is_empty() { self.struct_span_err( attrs[0].span, - &format!("trailing attribute after generic parameter"), + "trailing attribute after generic parameter", ) .span_label(attrs[0].span, "attributes must go before parameters") .emit(); diff --git a/src/test/ui/parser/qpath-in-type-args.rs b/src/test/ui/parser/qpath-in-type-args.rs new file mode 100644 index 0000000000000..d678d2c38f7b8 --- /dev/null +++ b/src/test/ui/parser/qpath-in-type-args.rs @@ -0,0 +1,11 @@ +trait Tr { + type TrSubtype; +} + +struct Bar<'a, Item: Tr, ::TrSubtype: 'a> { +//~^ ERROR qualified paths are not allowed in generic parameters + item: Item, + item_sub: &'a ::TrSubtype, +} + +fn main() {} diff --git a/src/test/ui/parser/qpath-in-type-args.stderr b/src/test/ui/parser/qpath-in-type-args.stderr new file mode 100644 index 0000000000000..399a9fa370e1c --- /dev/null +++ b/src/test/ui/parser/qpath-in-type-args.stderr @@ -0,0 +1,10 @@ +error: qualified paths are not allowed in generic parameters + --> $DIR/qpath-in-type-args.rs:5:26 + | +LL | struct Bar<'a, Item: Tr, ::TrSubtype: 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: move this constraint to the `where` clause + +error: aborting due to previous error + From c184f345ac66ceeca2adcd04fc4fe4e59ae4b4d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 28 Apr 2019 17:31:16 -0700 Subject: [PATCH 2/2] review comment --- src/test/ui/parser/qpath-in-type-args.rs | 6 +++--- src/test/ui/parser/qpath-in-type-args.stderr | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/ui/parser/qpath-in-type-args.rs b/src/test/ui/parser/qpath-in-type-args.rs index d678d2c38f7b8..902496da02efd 100644 --- a/src/test/ui/parser/qpath-in-type-args.rs +++ b/src/test/ui/parser/qpath-in-type-args.rs @@ -1,11 +1,11 @@ trait Tr { - type TrSubtype; + type TrAssoc; } -struct Bar<'a, Item: Tr, ::TrSubtype: 'a> { +struct Bar<'a, Item: Tr, ::TrAssoc: 'a> { //~^ ERROR qualified paths are not allowed in generic parameters item: Item, - item_sub: &'a ::TrSubtype, + item_sub: &'a ::TrAssoc, } fn main() {} diff --git a/src/test/ui/parser/qpath-in-type-args.stderr b/src/test/ui/parser/qpath-in-type-args.stderr index 399a9fa370e1c..ad8ab133f93db 100644 --- a/src/test/ui/parser/qpath-in-type-args.stderr +++ b/src/test/ui/parser/qpath-in-type-args.stderr @@ -1,8 +1,8 @@ error: qualified paths are not allowed in generic parameters --> $DIR/qpath-in-type-args.rs:5:26 | -LL | struct Bar<'a, Item: Tr, ::TrSubtype: 'a> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct Bar<'a, Item: Tr, ::TrAssoc: 'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: move this constraint to the `where` clause