From f3ef4a416d162c0a3f18c627d27fdb3676df336c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 06:44:24 +0100 Subject: [PATCH 01/28] extract parse_ty_tuple_or_parens --- src/librustc_parse/parser/ty.rs | 82 ++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 6f7ab0542d5fa..ae660432923e5 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -74,44 +74,7 @@ impl<'a> Parser<'a> { let lo = self.token.span; let mut impl_dyn_multi = false; let kind = if self.eat(&token::OpenDelim(token::Paren)) { - // `(TYPE)` is a parenthesized type. - // `(TYPE,)` is a tuple with a single field of type TYPE. - let mut ts = vec![]; - let mut last_comma = false; - while self.token != token::CloseDelim(token::Paren) { - ts.push(self.parse_ty()?); - if self.eat(&token::Comma) { - last_comma = true; - } else { - last_comma = false; - break; - } - } - let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; - self.expect(&token::CloseDelim(token::Paren))?; - - if ts.len() == 1 && !last_comma { - let ty = ts.into_iter().nth(0).unwrap().into_inner(); - let maybe_bounds = allow_plus && self.token.is_like_plus(); - match ty.kind { - // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, ref path) if maybe_bounds => { - self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)? - } - TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) - if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - let path = match bounds[0] { - GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), - GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), - }; - self.parse_remaining_bounds(Vec::new(), path, lo, true)? - } - // `(TYPE)` - _ => TyKind::Paren(P(ty)) - } - } else { - TyKind::Tup(ts) - } + self.parse_ty_tuple_or_parens(allow_plus)? } else if self.eat(&token::Not) { // Never type `!` TyKind::Never @@ -242,6 +205,49 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery) } + /// Parses either: + /// - `(TYPE)`, a parenthesized type. + /// - `(TYPE,)`, a tuple with a single field of type TYPE. + fn parse_ty_tuple_or_parens(&mut self, allow_plus: bool) -> PResult<'a, TyKind> { + let lo = self.token.span; + let mut ts = vec![]; + let mut last_comma = false; + while self.token != token::CloseDelim(token::Paren) { + ts.push(self.parse_ty()?); + if self.eat(&token::Comma) { + last_comma = true; + } else { + last_comma = false; + break; + } + } + let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; + self.expect(&token::CloseDelim(token::Paren))?; + + if ts.len() == 1 && !last_comma { + let ty = ts.into_iter().nth(0).unwrap().into_inner(); + let maybe_bounds = allow_plus && self.token.is_like_plus(); + match ty.kind { + // `(TY_BOUND_NOPAREN) + BOUND + ...`. + TyKind::Path(None, ref path) if maybe_bounds => { + self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true) + } + TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + let path = match bounds[0] { + GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), + GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), + }; + self.parse_remaining_bounds(Vec::new(), path, lo, true) + } + // `(TYPE)` + _ => Ok(TyKind::Paren(P(ty))) + } + } else { + Ok(TyKind::Tup(ts)) + } + } + fn parse_remaining_bounds(&mut self, generic_params: Vec, path: ast::Path, lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); From c67c30dba60866770f3babc7a33470a5dfe5ea77 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 07:55:38 +0100 Subject: [PATCH 02/28] refactor parse_ty_tuple_or_parens --- src/librustc_parse/parser/ty.rs | 40 +++++++++++++-------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index ae660432923e5..716bdf7bb1259 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -73,8 +73,8 @@ impl<'a> Parser<'a> { let lo = self.token.span; let mut impl_dyn_multi = false; - let kind = if self.eat(&token::OpenDelim(token::Paren)) { - self.parse_ty_tuple_or_parens(allow_plus)? + let kind = if self.check(&token::OpenDelim(token::Paren)) { + self.parse_ty_tuple_or_parens(lo, allow_plus)? } else if self.eat(&token::Not) { // Never type `!` TyKind::Never @@ -208,34 +208,26 @@ impl<'a> Parser<'a> { /// Parses either: /// - `(TYPE)`, a parenthesized type. /// - `(TYPE,)`, a tuple with a single field of type TYPE. - fn parse_ty_tuple_or_parens(&mut self, allow_plus: bool) -> PResult<'a, TyKind> { - let lo = self.token.span; - let mut ts = vec![]; - let mut last_comma = false; - while self.token != token::CloseDelim(token::Paren) { - ts.push(self.parse_ty()?); - if self.eat(&token::Comma) { - last_comma = true; - } else { - last_comma = false; - break; - } - } - let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus; - self.expect(&token::CloseDelim(token::Paren))?; + fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> { + let mut trailing_plus = false; + let (ts, trailing) = self.parse_paren_comma_seq(|p| { + let ty = p.parse_ty()?; + trailing_plus = p.prev_token_kind == PrevTokenKind::Plus; + Ok(ty) + })?; - if ts.len() == 1 && !last_comma { + if ts.len() == 1 && !trailing { let ty = ts.into_iter().nth(0).unwrap().into_inner(); let maybe_bounds = allow_plus && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. - TyKind::Path(None, ref path) if maybe_bounds => { - self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true) + TyKind::Path(None, path) if maybe_bounds => { + self.parse_remaining_bounds(Vec::new(), path, lo, true) } - TyKind::TraitObject(ref bounds, TraitObjectSyntax::None) - if maybe_bounds && bounds.len() == 1 && !trailing_plus => { - let path = match bounds[0] { - GenericBound::Trait(ref pt, ..) => pt.trait_ref.path.clone(), + TyKind::TraitObject(mut bounds, TraitObjectSyntax::None) + if maybe_bounds && bounds.len() == 1 && !trailing_plus => { + let path = match bounds.remove(0) { + GenericBound::Trait(pt, ..) => pt.trait_ref.path, GenericBound::Outlives(..) => self.bug("unexpected lifetime bound"), }; self.parse_remaining_bounds(Vec::new(), path, lo, true) From 3838b602f5baa2fe37f8cf77dbf43b73a0777677 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 07:58:45 +0100 Subject: [PATCH 03/28] parse_ptr -> parse_ty_ptr & refactor --- src/librustc_parse/parser/ty.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 716bdf7bb1259..9ea5a88ddadf9 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -79,8 +79,7 @@ impl<'a> Parser<'a> { // Never type `!` TyKind::Never } else if self.eat(&token::BinOp(token::Star)) { - // Raw pointer - TyKind::Ptr(self.parse_ptr()?) + self.parse_ty_ptr()? } else if self.eat(&token::OpenDelim(token::Bracket)) { // Array or slice let t = self.parse_ty()?; @@ -251,7 +250,8 @@ impl<'a> Parser<'a> { Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } - fn parse_ptr(&mut self) -> PResult<'a, MutTy> { + /// Parses a raw pointer type: `*[const | mut] $type`. + fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> { let mutbl = self.parse_const_or_mut().unwrap_or_else(|| { let span = self.prev_span; let msg = "expected mut or const in raw pointer type"; @@ -261,8 +261,8 @@ impl<'a> Parser<'a> { .emit(); Mutability::Immutable }); - let t = self.parse_ty_no_plus()?; - Ok(MutTy { ty: t, mutbl }) + let ty = self.parse_ty_no_plus()?; + Ok(TyKind::Ptr(MutTy { ty, mutbl })) } fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { From 211560d05c3be81b82d029d49cd23d0f6fef859e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:19:53 +0100 Subject: [PATCH 04/28] extract parse_array_or_slice_ty --- src/librustc_parse/parser/expr.rs | 11 ++++----- src/librustc_parse/parser/item.rs | 7 ++---- src/librustc_parse/parser/ty.rs | 37 ++++++++++++------------------- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 159c2121d36c8..71c9e58f58fd7 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -90,6 +90,10 @@ impl<'a> Parser<'a> { self.parse_expr_res(Restrictions::empty(), None) } + pub(super) fn parse_anon_const_expr(&mut self) -> PResult<'a, AnonConst> { + self.parse_expr().map(|value| AnonConst { id: DUMMY_NODE_ID, value }) + } + fn parse_expr_catch_underscore(&mut self) -> PResult<'a, P> { match self.parse_expr() { Ok(expr) => Ok(expr), @@ -109,7 +113,7 @@ impl<'a> Parser<'a> { } } - /// Parses a sequence of expressions bounded by parentheses. + /// Parses a sequence of expressions delimited by parentheses. fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec>> { self.parse_paren_comma_seq(|p| { p.parse_expr_catch_underscore() @@ -955,10 +959,7 @@ impl<'a> Parser<'a> { let first_expr = self.parse_expr()?; if self.eat(&token::Semi) { // Repeating array syntax: `[ 0; 512 ]` - let count = AnonConst { - id: DUMMY_NODE_ID, - value: self.parse_expr()?, - }; + let count = self.parse_anon_const_expr()?; self.expect(close)?; ExprKind::Repeat(first_expr, count) } else if self.eat(&token::Comma) { diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 229ca07f13b51..2a4c6f110c4e8 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -5,7 +5,7 @@ use crate::maybe_whole; use rustc_errors::{PResult, Applicability, DiagnosticBuilder, StashKey}; use rustc_error_codes::*; -use syntax::ast::{self, DUMMY_NODE_ID, Ident, AttrVec, Attribute, AttrKind, AttrStyle, AnonConst}; +use syntax::ast::{self, DUMMY_NODE_ID, Ident, AttrVec, Attribute, AttrKind, AttrStyle}; use syntax::ast::{AssocItem, AssocItemKind, Item, ItemKind, UseTree, UseTreeKind}; use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit}; use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; @@ -1317,10 +1317,7 @@ impl<'a> Parser<'a> { }; let disr_expr = if self.eat(&token::Eq) { - Some(AnonConst { - id: DUMMY_NODE_ID, - value: self.parse_expr()?, - }) + Some(self.parse_anon_const_expr()?) } else { None }; diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 9ea5a88ddadf9..c3d934d350327 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -8,7 +8,7 @@ use rustc_error_codes::*; use syntax::ptr::P; use syntax::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident}; use syntax::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef}; -use syntax::ast::{Mutability, AnonConst, Mac}; +use syntax::ast::{Mutability, Mac}; use syntax::token::{self, Token}; use syntax::struct_span_err; use syntax_pos::source_map::Span; @@ -81,18 +81,7 @@ impl<'a> Parser<'a> { } else if self.eat(&token::BinOp(token::Star)) { self.parse_ty_ptr()? } else if self.eat(&token::OpenDelim(token::Bracket)) { - // Array or slice - let t = self.parse_ty()?; - // Parse optional `; EXPR` in `[TYPE; EXPR]` - let t = match self.maybe_parse_fixed_length_of_vec()? { - None => TyKind::Slice(t), - Some(length) => TyKind::Array(t, AnonConst { - id: ast::DUMMY_NODE_ID, - value: length, - }), - }; - self.expect(&token::CloseDelim(token::Bracket))?; - t + self.parse_array_or_slice_ty()? } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { // Reference self.expect_and()?; @@ -101,12 +90,9 @@ impl<'a> Parser<'a> { // `typeof(EXPR)` // In order to not be ambiguous, the type must be surrounded by parens. self.expect(&token::OpenDelim(token::Paren))?; - let e = AnonConst { - id: ast::DUMMY_NODE_ID, - value: self.parse_expr()?, - }; + let expr = self.parse_anon_const_expr()?; self.expect(&token::CloseDelim(token::Paren))?; - TyKind::Typeof(e) + TyKind::Typeof(expr) } else if self.eat_keyword(kw::Underscore) { // A type to be inferred `_` TyKind::Infer @@ -265,12 +251,17 @@ impl<'a> Parser<'a> { Ok(TyKind::Ptr(MutTy { ty, mutbl })) } - fn maybe_parse_fixed_length_of_vec(&mut self) -> PResult<'a, Option>> { - if self.eat(&token::Semi) { - Ok(Some(self.parse_expr()?)) + /// Parses an array (`[TYPE; EXPR]`) or slice (`[TYPE]`) type. + /// The opening `[` bracket is already eaten. + fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> { + let elt_ty = self.parse_ty()?; + let ty = if self.eat(&token::Semi) { + TyKind::Array(elt_ty, self.parse_anon_const_expr()?) } else { - Ok(None) - } + TyKind::Slice(elt_ty) + }; + self.expect(&token::CloseDelim(token::Bracket))?; + Ok(ty) } fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { From e08886d251205826a3f6ab6d331c123a9a53268d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:23:10 +0100 Subject: [PATCH 05/28] extract parse_typeof_ty --- src/librustc_parse/parser/ty.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c3d934d350327..624719d6ca53b 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -87,12 +87,7 @@ impl<'a> Parser<'a> { self.expect_and()?; self.parse_borrowed_pointee()? } else if self.eat_keyword_noexpect(kw::Typeof) { - // `typeof(EXPR)` - // In order to not be ambiguous, the type must be surrounded by parens. - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_anon_const_expr()?; - self.expect(&token::CloseDelim(token::Paren))?; - TyKind::Typeof(expr) + self.parse_typeof_ty()? } else if self.eat_keyword(kw::Underscore) { // A type to be inferred `_` TyKind::Infer @@ -268,7 +263,16 @@ impl<'a> Parser<'a> { let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; let mutbl = self.parse_mutability(); let ty = self.parse_ty_no_plus()?; - return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })); + Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })) + } + + // Parses the `typeof(EXPR)`. + // To avoid ambiguity, the type is surrounded by parenthesis. + fn parse_typeof_ty(&mut self) -> PResult<'a, TyKind> { + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_anon_const_expr()?; + self.expect(&token::CloseDelim(token::Paren))?; + Ok(TyKind::Typeof(expr)) } /// Is the current token one of the keywords that signals a bare function type? From edb7b96c84312ebc05f1e27515543c9f9365ba58 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:29:12 +0100 Subject: [PATCH 06/28] extract parse_impl_ty --- src/librustc_parse/parser/ty.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 624719d6ca53b..c3fc16e0725ba 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -98,7 +98,6 @@ impl<'a> Parser<'a> { // Function pointer type or bound list (trait object type) starting with a poly-trait. // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` // `for<'lt> Trait1<'lt> + Trait2 + 'a` - let lo = self.token.span; let lifetime_defs = self.parse_late_bound_lifetime_defs()?; if self.token_is_bare_fn_keyword() { self.parse_ty_bare_fn(lifetime_defs)? @@ -108,10 +107,7 @@ impl<'a> Parser<'a> { self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)? } } else if self.eat_keyword(kw::Impl) { - // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds(None)?; - impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds) + self.parse_impl_ty(&mut impl_dyn_multi)? } else if self.check_keyword(kw::Dyn) && (self.token.span.rust_2018() || self.look_ahead(1, |t| t.can_begin_bound() && @@ -312,6 +308,14 @@ impl<'a> Parser<'a> { }))) } + /// Parses an `impl B0 + ... + Bn` type. + fn parse_impl_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { + // Always parse bounds greedily for better error recovery. + let bounds = self.parse_generic_bounds(None)?; + *impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; + Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) + } + pub(super) fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) From b7071f2bc04530c055b2198efb08f2478af32c19 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:38:23 +0100 Subject: [PATCH 07/28] extract parse_dyn_ty --- src/librustc_parse/parser/ty.rs | 40 ++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c3fc16e0725ba..e88bfc17dd6eb 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -108,20 +108,14 @@ impl<'a> Parser<'a> { } } else if self.eat_keyword(kw::Impl) { self.parse_impl_ty(&mut impl_dyn_multi)? - } else if self.check_keyword(kw::Dyn) && - (self.token.span.rust_2018() || - self.look_ahead(1, |t| t.can_begin_bound() && - !can_continue_type_after_non_fn_ident(t))) { - self.bump(); // `dyn` - // Always parse bounds greedily for better error recovery. - let bounds = self.parse_generic_bounds(None)?; - impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; - TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn) - } else if self.check(&token::Question) || - self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) { + } else if self.is_explicit_dyn_type() { + self.parse_dyn_ty(&mut impl_dyn_multi)? + } else if self.check(&token::Question) + || self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus()) + { // Bound list (trait object type) - TyKind::TraitObject(self.parse_generic_bounds_common(allow_plus, None)?, - TraitObjectSyntax::None) + let bounds = self.parse_generic_bounds_common(allow_plus, None)?; + TyKind::TraitObject(bounds, TraitObjectSyntax::None) } else if self.eat_lt() { // Qualified path let (qself, path) = self.parse_qpath(PathStyle::Type)?; @@ -316,6 +310,26 @@ impl<'a> Parser<'a> { Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) } + /// Is a `dyn B0 + ... + Bn` type allowed here? + fn is_explicit_dyn_type(&mut self) -> bool { + self.check_keyword(kw::Dyn) + && (self.token.span.rust_2018() + || self.look_ahead(1, |t| { + t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t) + })) + } + + /// Parses a `dyn B0 + ... + Bn` type. + /// + /// Note that this does *not* parse bare trait objects. + fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { + self.bump(); // `dyn` + // Always parse bounds greedily for better error recovery. + let bounds = self.parse_generic_bounds(None)?; + *impl_dyn_multi = bounds.len() > 1 || self.prev_token_kind == PrevTokenKind::Plus; + Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)) + } + pub(super) fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) From 85d3ed9c90cdf6802d3425f08eddb3f4f38d2429 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 08:49:20 +0100 Subject: [PATCH 08/28] extract parse_path_start_ty --- src/librustc_parse/parser/ty.rs | 47 ++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index e88bfc17dd6eb..ddbb9afa02b32 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -121,27 +121,7 @@ impl<'a> Parser<'a> { let (qself, path) = self.parse_qpath(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { - // Simple path - let path = self.parse_path(PathStyle::Type)?; - if self.eat(&token::Not) { - // Macro invocation in type position - let args = self.parse_mac_args()?; - let mac = Mac { - path, - args, - prior_type_ascription: self.last_type_ascription, - }; - TyKind::Mac(mac) - } else { - // Just a type path or bound list (trait object type) starting with a trait. - // `Type` - // `Trait1 + Trait2 + 'a` - if allow_plus && self.check_plus() { - self.parse_remaining_bounds(Vec::new(), path, lo, true)? - } else { - TyKind::Path(None, path) - } - } + self.parse_path_start_ty(lo, allow_plus)? } else if self.eat(&token::DotDotDot) { if allow_c_variadic { TyKind::CVarArgs @@ -330,6 +310,31 @@ impl<'a> Parser<'a> { Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)) } + /// Parses a type starting with a path. + /// + /// This can be: + /// 1. a type macro, `mac!(...)`, + /// 2. a bare trait object, `B0 + ... + Bn`, + /// 3. or a path, `path::to::MyType`. + fn parse_path_start_ty(&mut self, lo: Span, allow_plus: bool) -> PResult<'a, TyKind> { + // Simple path + let path = self.parse_path(PathStyle::Type)?; + if self.eat(&token::Not) { + // Macro invocation in type position + Ok(TyKind::Mac(Mac { + path, + args: self.parse_mac_args()?, + prior_type_ascription: self.last_type_ascription, + })) + } else if allow_plus && self.check_plus() { + // `Trait1 + Trait2 + 'a` + self.parse_remaining_bounds(Vec::new(), path, lo, true) + } else { + // Just a type path. + Ok(TyKind::Path(None, path)) + } + } + pub(super) fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) From 6f1f6a6c33560ec9864ae367c8e2732cddbb2626 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:01:26 +0100 Subject: [PATCH 09/28] extract error_illegal_c_variadic_ty --- src/librustc_parse/parser/ty.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index ddbb9afa02b32..840461d75be01 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -128,14 +128,7 @@ impl<'a> Parser<'a> { } else { // FIXME(Centril): Should we just allow `...` syntactically // anywhere in a type and use semantic restrictions instead? - struct_span_err!( - self.sess.span_diagnostic, - lo.to(self.prev_span), - E0743, - "C-variadic type `...` may not be nested inside another type", - ) - .emit(); - + self.error_illegal_c_varadic_ty(lo); TyKind::Err } } else { @@ -335,6 +328,16 @@ impl<'a> Parser<'a> { } } + fn error_illegal_c_varadic_ty(&self, lo: Span) { + struct_span_err!( + self.sess.span_diagnostic, + lo.to(self.prev_span), + E0743, + "C-variadic type `...` may not be nested inside another type", + ) + .emit(); + } + pub(super) fn parse_generic_bounds(&mut self, colon_span: Option) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) From 3b1fab8c1f0ef78d90fd27d8ec0e6950c050d259 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:08:19 +0100 Subject: [PATCH 10/28] parse_ty_common: .fatal -> .struct_span_err --- src/librustc_parse/parser/ty.rs | 2 +- src/test/ui/type/ascription/issue-47666.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 840461d75be01..d9938a81240dc 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -133,7 +133,7 @@ impl<'a> Parser<'a> { } } else { let msg = format!("expected type, found {}", self.this_token_descr()); - let mut err = self.fatal(&msg); + let mut err = self.struct_span_err(self.token.span, &msg); err.span_label(self.token.span, "expected type"); self.maybe_annotate_with_ascription(&mut err, true); return Err(err); diff --git a/src/test/ui/type/ascription/issue-47666.stderr b/src/test/ui/type/ascription/issue-47666.stderr index 2f052341faead..648635f0c32fa 100644 --- a/src/test/ui/type/ascription/issue-47666.stderr +++ b/src/test/ui/type/ascription/issue-47666.stderr @@ -11,7 +11,7 @@ LL | let _ = Option:Some(vec![0, 1]); | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` = note: for more information, see https://github.com/rust-lang/rust/issues/23416 - = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error From 3f499a97e43b9f1cd23233de542419921ea4b6d0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:10:17 +0100 Subject: [PATCH 11/28] parser/ty.rs: minor formatting tweaks --- src/librustc_parse/parser/ty.rs | 35 ++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index d9938a81240dc..a4c1f530ef8f2 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -183,8 +183,13 @@ impl<'a> Parser<'a> { } } - fn parse_remaining_bounds(&mut self, generic_params: Vec, path: ast::Path, - lo: Span, parse_plus: bool) -> PResult<'a, TyKind> { + fn parse_remaining_bounds( + &mut self, + generic_params: Vec, + path: ast::Path, + lo: Span, + parse_plus: bool, + ) -> PResult<'a, TyKind> { let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span)); let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { @@ -338,8 +343,10 @@ impl<'a> Parser<'a> { .emit(); } - pub(super) fn parse_generic_bounds(&mut self, - colon_span: Option) -> PResult<'a, GenericBounds> { + pub(super) fn parse_generic_bounds( + &mut self, + colon_span: Option, + ) -> PResult<'a, GenericBounds> { self.parse_generic_bounds_common(true, colon_span) } @@ -351,20 +358,24 @@ impl<'a> Parser<'a> { /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) /// ``` - fn parse_generic_bounds_common(&mut self, - allow_plus: bool, - colon_span: Option) -> PResult<'a, GenericBounds> { + fn parse_generic_bounds_common( + &mut self, + allow_plus: bool, + colon_span: Option, + ) -> PResult<'a, GenericBounds> { let mut bounds = Vec::new(); let mut negative_bounds = Vec::new(); let mut last_plus_span = None; let mut was_negative = false; loop { // This needs to be synchronized with `TokenKind::can_begin_bound`. - let is_bound_start = self.check_path() || self.check_lifetime() || - self.check(&token::Not) || // used for error reporting only - self.check(&token::Question) || - self.check_keyword(kw::For) || - self.check(&token::OpenDelim(token::Paren)); + let is_bound_start = self.check_path() + || self.check_lifetime() + || self.check(&token::Not) // Used for error reporting only. + || self.check(&token::Question) + || self.check_keyword(kw::For) + || self.check(&token::OpenDelim(token::Paren)); + if is_bound_start { let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); From b484faefab8bfd27d7ccf28aa5597e85591d2a90 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:18:34 +0100 Subject: [PATCH 12/28] extract error_opt_out_lifetime --- src/librustc_parse/parser/ty.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index a4c1f530ef8f2..b9537100ce174 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -383,10 +383,7 @@ impl<'a> Parser<'a> { let is_negative = self.eat(&token::Not); let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.token.is_lifetime() { - if let Some(question_span) = question { - self.span_err(question_span, - "`?` may only modify trait bounds, not lifetime bounds"); - } + self.error_opt_out_lifetime(question); bounds.push(GenericBound::Outlives(self.expect_lifetime())); if has_parens { let inner_span = inner_lo.to(self.prev_span); @@ -473,6 +470,13 @@ impl<'a> Parser<'a> { return Ok(bounds); } + fn error_opt_out_lifetime(&self, question: Option) { + if let Some(span) = question { + self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") + .emit(); + } + } + pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; From a11252ae266ded70e47ede20e68a41f611d2280b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:29:17 +0100 Subject: [PATCH 13/28] extract recover_paren_lifetime --- src/librustc_parse/parser/ty.rs | 36 +++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index b9537100ce174..2b642ad2de7a3 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -386,21 +386,7 @@ impl<'a> Parser<'a> { self.error_opt_out_lifetime(question); bounds.push(GenericBound::Outlives(self.expect_lifetime())); if has_parens { - let inner_span = inner_lo.to(self.prev_span); - self.expect(&token::CloseDelim(token::Paren))?; - let mut err = self.struct_span_err( - lo.to(self.prev_span), - "parenthesized lifetime bounds are not supported" - ); - if let Ok(snippet) = self.span_to_snippet(inner_span) { - err.span_suggestion_short( - lo.to(self.prev_span), - "remove the parentheses", - snippet.to_owned(), - Applicability::MachineApplicable - ); - } - err.emit(); + self.recover_paren_lifetime(lo, inner_lo)?; } } else { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; @@ -477,6 +463,26 @@ impl<'a> Parser<'a> { } } + /// Recover on `('lifetime)` with `(` already eaten. + fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()> { + let inner_span = inner_lo.to(self.prev_span); + self.expect(&token::CloseDelim(token::Paren))?; + let mut err = self.struct_span_err( + lo.to(self.prev_span), + "parenthesized lifetime bounds are not supported" + ); + if let Ok(snippet) = self.span_to_snippet(inner_span) { + err.span_suggestion_short( + lo.to(self.prev_span), + "remove the parentheses", + snippet.to_owned(), + Applicability::MachineApplicable + ); + } + err.emit(); + Ok(()) + } + pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; From e61cb44f2f55a79562d1c714b42620c81c962d5d Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 09:42:32 +0100 Subject: [PATCH 14/28] parse_generic_bounds_common: dedent --- src/librustc_parse/parser/ty.rs | 64 ++++++++++++++++----------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 2b642ad2de7a3..b58c16c78e66a 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -376,42 +376,42 @@ impl<'a> Parser<'a> { || self.check_keyword(kw::For) || self.check(&token::OpenDelim(token::Paren)); - if is_bound_start { - let lo = self.token.span; - let has_parens = self.eat(&token::OpenDelim(token::Paren)); - let inner_lo = self.token.span; - let is_negative = self.eat(&token::Not); - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if self.token.is_lifetime() { - self.error_opt_out_lifetime(question); - bounds.push(GenericBound::Outlives(self.expect_lifetime())); - if has_parens { - self.recover_paren_lifetime(lo, inner_lo)?; + if !is_bound_start { + break; + } + + let lo = self.token.span; + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let inner_lo = self.token.span; + let is_negative = self.eat(&token::Not); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + self.error_opt_out_lifetime(question); + bounds.push(GenericBound::Outlives(self.expect_lifetime())); + if has_parens { + self.recover_paren_lifetime(lo, inner_lo)?; + } + } else { + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + } + let poly_span = lo.to(self.prev_span); + if is_negative { + was_negative = true; + if let Some(sp) = last_plus_span.or(colon_span) { + negative_bounds.push(sp.to(poly_span)); } } else { - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; - } - let poly_span = lo.to(self.prev_span); - if is_negative { - was_negative = true; - if let Some(sp) = last_plus_span.or(colon_span) { - negative_bounds.push(sp.to(poly_span)); - } + let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe } else { - let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe - } else { - TraitBoundModifier::None - }; - bounds.push(GenericBound::Trait(poly_trait, modifier)); - } + TraitBoundModifier::None + }; + bounds.push(GenericBound::Trait(poly_trait, modifier)); } - } else { - break } if !allow_plus || !self.eat_plus() { From fd89104966d6ea6a1bbc14d697b9197f06614d12 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 10:04:31 +0100 Subject: [PATCH 15/28] extract can_begin_bound --- src/librustc_parse/parser/ty.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index b58c16c78e66a..ca8dd62cc6a02 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -367,19 +367,7 @@ impl<'a> Parser<'a> { let mut negative_bounds = Vec::new(); let mut last_plus_span = None; let mut was_negative = false; - loop { - // This needs to be synchronized with `TokenKind::can_begin_bound`. - let is_bound_start = self.check_path() - || self.check_lifetime() - || self.check(&token::Not) // Used for error reporting only. - || self.check(&token::Question) - || self.check_keyword(kw::For) - || self.check(&token::OpenDelim(token::Paren)); - - if !is_bound_start { - break; - } - + while self.can_begin_bound() { let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; @@ -456,6 +444,17 @@ impl<'a> Parser<'a> { return Ok(bounds); } + /// Can the current token begin a bound? + fn can_begin_bound(&mut self) -> bool { + // This needs to be synchronized with `TokenKind::can_begin_bound`. + self.check_path() + || self.check_lifetime() + || self.check(&token::Not) // Used for error reporting only. + || self.check(&token::Question) + || self.check_keyword(kw::For) + || self.check(&token::OpenDelim(token::Paren)) + } + fn error_opt_out_lifetime(&self, question: Option) { if let Some(span) = question { self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") From 8a9a992a6430371cb71a8abddd6839f6f1dde699 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 10:32:38 +0100 Subject: [PATCH 16/28] extract parse_generic_bound --- src/librustc_parse/parser/ty.rs | 101 +++++++++++++++++++------------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index ca8dd62cc6a02..f0a1b36bc3624 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -352,12 +352,7 @@ impl<'a> Parser<'a> { /// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`. /// - /// ``` - /// BOUND = TY_BOUND | LT_BOUND - /// LT_BOUND = LIFETIME (e.g., `'a`) - /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) - /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) - /// ``` + /// See `parse_generic_bound` for the `BOUND` grammar. fn parse_generic_bounds_common( &mut self, allow_plus: bool, @@ -368,39 +363,13 @@ impl<'a> Parser<'a> { let mut last_plus_span = None; let mut was_negative = false; while self.can_begin_bound() { - let lo = self.token.span; - let has_parens = self.eat(&token::OpenDelim(token::Paren)); - let inner_lo = self.token.span; - let is_negative = self.eat(&token::Not); - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if self.token.is_lifetime() { - self.error_opt_out_lifetime(question); - bounds.push(GenericBound::Outlives(self.expect_lifetime())); - if has_parens { - self.recover_paren_lifetime(lo, inner_lo)?; - } - } else { - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; - } - let poly_span = lo.to(self.prev_span); - if is_negative { - was_negative = true; - if let Some(sp) = last_plus_span.or(colon_span) { - negative_bounds.push(sp.to(poly_span)); - } - } else { - let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe - } else { - TraitBoundModifier::None - }; - bounds.push(GenericBound::Trait(poly_trait, modifier)); - } - } + self.parse_generic_bound( + colon_span, + last_plus_span, + &mut bounds, + &mut negative_bounds, + &mut was_negative, + )?; if !allow_plus || !self.eat_plus() { break @@ -441,7 +410,7 @@ impl<'a> Parser<'a> { err.emit(); } - return Ok(bounds); + Ok(bounds) } /// Can the current token begin a bound? @@ -455,6 +424,58 @@ impl<'a> Parser<'a> { || self.check(&token::OpenDelim(token::Paren)) } + /// Parses a bound according to the grammar: + /// + /// ``` + /// BOUND = TY_BOUND | LT_BOUND + /// LT_BOUND = LIFETIME (e.g., `'a`) + /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) + /// ``` + fn parse_generic_bound( + &mut self, + colon_span: Option, + last_plus_span: Option, + bounds: &mut Vec, + negative_bounds: &mut Vec, + was_negative: &mut bool, + ) -> PResult<'a, ()> { + let lo = self.token.span; + let has_parens = self.eat(&token::OpenDelim(token::Paren)); + let inner_lo = self.token.span; + let is_negative = self.eat(&token::Not); + let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + if self.token.is_lifetime() { + self.error_opt_out_lifetime(question); + bounds.push(GenericBound::Outlives(self.expect_lifetime())); + if has_parens { + self.recover_paren_lifetime(lo, inner_lo)?; + } + } else { + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + } + let poly_span = lo.to(self.prev_span); + if is_negative { + *was_negative = true; + if let Some(sp) = last_plus_span.or(colon_span) { + negative_bounds.push(sp.to(poly_span)); + } + } else { + let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); + let modifier = if question.is_some() { + TraitBoundModifier::Maybe + } else { + TraitBoundModifier::None + }; + bounds.push(GenericBound::Trait(poly_trait, modifier)); + } + } + Ok(()) + } + fn error_opt_out_lifetime(&self, question: Option) { if let Some(span) = question { self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") From 18e5b2f98c7768f0342333e7b6bb6c506f663515 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:04:26 +0100 Subject: [PATCH 17/28] functionalize parse_generic_bound --- src/librustc_parse/parser/ty.rs | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index f0a1b36bc3624..72f831aab0678 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -363,13 +363,15 @@ impl<'a> Parser<'a> { let mut last_plus_span = None; let mut was_negative = false; while self.can_begin_bound() { - self.parse_generic_bound( - colon_span, - last_plus_span, - &mut bounds, - &mut negative_bounds, - &mut was_negative, - )?; + match self.parse_generic_bound(colon_span, last_plus_span)? { + Ok(bound) => bounds.push(bound), + Err(neg_sp) => { + was_negative = true; + if let Some(neg_sp) = neg_sp { + negative_bounds.push(neg_sp); + } + } + } if !allow_plus || !self.eat_plus() { break @@ -436,10 +438,7 @@ impl<'a> Parser<'a> { &mut self, colon_span: Option, last_plus_span: Option, - bounds: &mut Vec, - negative_bounds: &mut Vec, - was_negative: &mut bool, - ) -> PResult<'a, ()> { + ) -> PResult<'a, Result>> { let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; @@ -447,10 +446,11 @@ impl<'a> Parser<'a> { let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.token.is_lifetime() { self.error_opt_out_lifetime(question); - bounds.push(GenericBound::Outlives(self.expect_lifetime())); + let bound = GenericBound::Outlives(self.expect_lifetime()); if has_parens { self.recover_paren_lifetime(lo, inner_lo)?; } + Ok(Ok(bound)) } else { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let path = self.parse_path(PathStyle::Type)?; @@ -459,10 +459,7 @@ impl<'a> Parser<'a> { } let poly_span = lo.to(self.prev_span); if is_negative { - *was_negative = true; - if let Some(sp) = last_plus_span.or(colon_span) { - negative_bounds.push(sp.to(poly_span)); - } + Ok(Err(last_plus_span.or(colon_span).map(|sp| sp.to(poly_span)))) } else { let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); let modifier = if question.is_some() { @@ -470,10 +467,9 @@ impl<'a> Parser<'a> { } else { TraitBoundModifier::None }; - bounds.push(GenericBound::Trait(poly_trait, modifier)); + Ok(Ok(GenericBound::Trait(poly_trait, modifier))) } } - Ok(()) } fn error_opt_out_lifetime(&self, question: Option) { From 1cfeb567735a0a6c6ec9a32cbaa1ea672db637b1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:08:04 +0100 Subject: [PATCH 18/28] parse_generic_bound: leave a FIXME --- src/librustc_parse/parser/ty.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 72f831aab0678..2c362294ad0c9 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -448,6 +448,8 @@ impl<'a> Parser<'a> { self.error_opt_out_lifetime(question); let bound = GenericBound::Outlives(self.expect_lifetime()); if has_parens { + // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, + // possibly introducing `GenericBound::Paren(P)`? self.recover_paren_lifetime(lo, inner_lo)?; } Ok(Ok(bound)) From 50e00c73ee7efee610fa1dfca85155f3ce81b91e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:19:24 +0100 Subject: [PATCH 19/28] extract parse_generic_ty_bound --- src/librustc_parse/parser/ty.rs | 39 ++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 2c362294ad0c9..a5ce46e9700f9 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -431,8 +431,6 @@ impl<'a> Parser<'a> { /// ``` /// BOUND = TY_BOUND | LT_BOUND /// LT_BOUND = LIFETIME (e.g., `'a`) - /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) - /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) /// ``` fn parse_generic_bound( &mut self, @@ -454,22 +452,11 @@ impl<'a> Parser<'a> { } Ok(Ok(bound)) } else { - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - let path = self.parse_path(PathStyle::Type)?; - if has_parens { - self.expect(&token::CloseDelim(token::Paren))?; - } - let poly_span = lo.to(self.prev_span); + let (poly_span, bound) = self.parse_generic_ty_bound(lo, has_parens, question)?; if is_negative { Ok(Err(last_plus_span.or(colon_span).map(|sp| sp.to(poly_span)))) } else { - let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); - let modifier = if question.is_some() { - TraitBoundModifier::Maybe - } else { - TraitBoundModifier::None - }; - Ok(Ok(GenericBound::Trait(poly_trait, modifier))) + Ok(Ok(bound)) } } } @@ -501,6 +488,28 @@ impl<'a> Parser<'a> { Ok(()) } + /// Parses a type bound according to: + /// ``` + /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) + /// TY_BOUND_NOPAREN = [?] [for] SIMPLE_PATH (e.g., `?for<'a: 'b> m::Trait<'a>`) + /// ``` + fn parse_generic_ty_bound( + &mut self, + lo: Span, + has_parens: bool, + question: Option, + ) -> PResult<'a, (Span, GenericBound)> { + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + if has_parens { + self.expect(&token::CloseDelim(token::Paren))?; + } + let poly_span = lo.to(self.prev_span); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); + let modifier = question.map_or(TraitBoundModifier::None, |_| TraitBoundModifier::Maybe); + Ok((poly_span, GenericBound::Trait(poly_trait, modifier))) + } + pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; From 4b073a1f4a61e69ed08ad116f5d545d4c553d235 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:28:57 +0100 Subject: [PATCH 20/28] extract parse_generic_lt_bound --- src/librustc_parse/parser/ty.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index a5ce46e9700f9..905bc204b5156 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -427,10 +427,8 @@ impl<'a> Parser<'a> { } /// Parses a bound according to the grammar: - /// /// ``` /// BOUND = TY_BOUND | LT_BOUND - /// LT_BOUND = LIFETIME (e.g., `'a`) /// ``` fn parse_generic_bound( &mut self, @@ -443,14 +441,7 @@ impl<'a> Parser<'a> { let is_negative = self.eat(&token::Not); let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; if self.token.is_lifetime() { - self.error_opt_out_lifetime(question); - let bound = GenericBound::Outlives(self.expect_lifetime()); - if has_parens { - // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, - // possibly introducing `GenericBound::Paren(P)`? - self.recover_paren_lifetime(lo, inner_lo)?; - } - Ok(Ok(bound)) + Ok(Ok(self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)?)) } else { let (poly_span, bound) = self.parse_generic_ty_bound(lo, has_parens, question)?; if is_negative { @@ -461,6 +452,27 @@ impl<'a> Parser<'a> { } } + /// Parses a lifetime ("outlives") bound, e.g. `'a`, according to: + /// ``` + /// LT_BOUND = LIFETIME + /// ``` + fn parse_generic_lt_bound( + &mut self, + lo: Span, + inner_lo: Span, + has_parens: bool, + question: Option, + ) -> PResult<'a, GenericBound> { + self.error_opt_out_lifetime(question); + let bound = GenericBound::Outlives(self.expect_lifetime()); + if has_parens { + // FIXME(Centril): Consider not erroring here and accepting `('lt)` instead, + // possibly introducing `GenericBound::Paren(P)`? + self.recover_paren_lifetime(lo, inner_lo)?; + } + Ok(bound) + } + fn error_opt_out_lifetime(&self, question: Option) { if let Some(span) = question { self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds") From f215ca9be63ad7d7b916115e729bacf927621cb8 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:49:25 +0100 Subject: [PATCH 21/28] simplify negative bound diagnostic --- src/librustc_parse/parser/ty.rs | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 905bc204b5156..eadaf8ad716d3 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -360,36 +360,24 @@ impl<'a> Parser<'a> { ) -> PResult<'a, GenericBounds> { let mut bounds = Vec::new(); let mut negative_bounds = Vec::new(); - let mut last_plus_span = None; - let mut was_negative = false; while self.can_begin_bound() { - match self.parse_generic_bound(colon_span, last_plus_span)? { + match self.parse_generic_bound()? { Ok(bound) => bounds.push(bound), - Err(neg_sp) => { - was_negative = true; - if let Some(neg_sp) = neg_sp { - negative_bounds.push(neg_sp); - } - } + Err(neg_sp) => negative_bounds.push(neg_sp), } - if !allow_plus || !self.eat_plus() { break - } else { - last_plus_span = Some(self.prev_span); } } - if !negative_bounds.is_empty() || was_negative { + if !negative_bounds.is_empty() { let negative_bounds_len = negative_bounds.len(); - let last_span = negative_bounds.last().map(|sp| *sp); + let last_span = *negative_bounds.last().unwrap(); let mut err = self.struct_span_err( negative_bounds, "negative trait bounds are not supported", ); - if let Some(sp) = last_span { - err.span_label(sp, "negative trait bounds are not supported"); - } + err.span_label(last_span, "negative trait bounds are not supported"); if let Some(bound_list) = colon_span { let bound_list = bound_list.to(self.prev_span); let mut new_bound_list = String::new(); @@ -432,9 +420,8 @@ impl<'a> Parser<'a> { /// ``` fn parse_generic_bound( &mut self, - colon_span: Option, - last_plus_span: Option, - ) -> PResult<'a, Result>> { + ) -> PResult<'a, Result> { + let anchor_lo = self.prev_span; let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; @@ -445,7 +432,7 @@ impl<'a> Parser<'a> { } else { let (poly_span, bound) = self.parse_generic_ty_bound(lo, has_parens, question)?; if is_negative { - Ok(Err(last_plus_span.or(colon_span).map(|sp| sp.to(poly_span)))) + Ok(Err(anchor_lo.to(poly_span))) } else { Ok(Ok(bound)) } From 4625ba4872e17a98ea11940fff0e50b3b880b815 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 11:57:18 +0100 Subject: [PATCH 22/28] simplify 'let question = ...;' --- src/librustc_parse/parser/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index eadaf8ad716d3..c972204587574 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -426,7 +426,7 @@ impl<'a> Parser<'a> { let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; let is_negative = self.eat(&token::Not); - let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; + let question = self.eat(&token::Question).then_some(self.prev_span); if self.token.is_lifetime() { Ok(Ok(self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)?)) } else { From b5f00beaa5a77ff8bccbe4330ea0b5047661cbf5 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 12:19:53 +0100 Subject: [PATCH 23/28] parse_generic_bounds: account for negative lifetime bounds --- src/librustc_parse/parser/ty.rs | 35 +++++++++---------- src/test/ui/issues/issue-58857.rs | 2 +- src/test/ui/issues/issue-58857.stderr | 6 ++-- src/test/ui/parser/issue-33418.fixed | 10 +++--- src/test/ui/parser/issue-33418.rs | 10 +++--- src/test/ui/parser/issue-33418.stderr | 30 ++++++++-------- ...-negative-outlives-bound-syntactic-fail.rs | 12 +++++++ ...ative-outlives-bound-syntactic-fail.stderr | 26 ++++++++++++++ 8 files changed, 83 insertions(+), 48 deletions(-) create mode 100644 src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.rs create mode 100644 src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index c972204587574..db9a0ada525b1 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -375,9 +375,9 @@ impl<'a> Parser<'a> { let last_span = *negative_bounds.last().unwrap(); let mut err = self.struct_span_err( negative_bounds, - "negative trait bounds are not supported", + "negative bounds are not supported", ); - err.span_label(last_span, "negative trait bounds are not supported"); + err.span_label(last_span, "negative bounds are not supported"); if let Some(bound_list) = colon_span { let bound_list = bound_list.to(self.prev_span); let mut new_bound_list = String::new(); @@ -392,7 +392,7 @@ impl<'a> Parser<'a> { } err.span_suggestion_hidden( bound_list, - &format!("remove the trait bound{}", pluralize!(negative_bounds_len)), + &format!("remove the bound{}", pluralize!(negative_bounds_len)), new_bound_list, Applicability::MachineApplicable, ); @@ -418,25 +418,23 @@ impl<'a> Parser<'a> { /// ``` /// BOUND = TY_BOUND | LT_BOUND /// ``` - fn parse_generic_bound( - &mut self, - ) -> PResult<'a, Result> { + fn parse_generic_bound(&mut self) -> PResult<'a, Result> { let anchor_lo = self.prev_span; let lo = self.token.span; let has_parens = self.eat(&token::OpenDelim(token::Paren)); let inner_lo = self.token.span; let is_negative = self.eat(&token::Not); let question = self.eat(&token::Question).then_some(self.prev_span); - if self.token.is_lifetime() { - Ok(Ok(self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)?)) + let bound = if self.token.is_lifetime() { + self.parse_generic_lt_bound(lo, inner_lo, has_parens, question)? } else { - let (poly_span, bound) = self.parse_generic_ty_bound(lo, has_parens, question)?; - if is_negative { - Ok(Err(anchor_lo.to(poly_span))) - } else { - Ok(Ok(bound)) - } - } + self.parse_generic_ty_bound(lo, has_parens, question)? + }; + Ok(if is_negative { + Err(anchor_lo.to(self.prev_span)) + } else { + Ok(bound) + }) } /// Parses a lifetime ("outlives") bound, e.g. `'a`, according to: @@ -497,16 +495,15 @@ impl<'a> Parser<'a> { lo: Span, has_parens: bool, question: Option, - ) -> PResult<'a, (Span, GenericBound)> { + ) -> PResult<'a, GenericBound> { let lifetime_defs = self.parse_late_bound_lifetime_defs()?; let path = self.parse_path(PathStyle::Type)?; if has_parens { self.expect(&token::CloseDelim(token::Paren))?; } - let poly_span = lo.to(self.prev_span); - let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); let modifier = question.map_or(TraitBoundModifier::None, |_| TraitBoundModifier::Maybe); - Ok((poly_span, GenericBound::Trait(poly_trait, modifier))) + Ok(GenericBound::Trait(poly_trait, modifier)) } pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { diff --git a/src/test/ui/issues/issue-58857.rs b/src/test/ui/issues/issue-58857.rs index 392e4ea0c2ecc..4350d7e5b403b 100644 --- a/src/test/ui/issues/issue-58857.rs +++ b/src/test/ui/issues/issue-58857.rs @@ -2,6 +2,6 @@ struct Conj {a : A} trait Valid {} impl Conj{} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported fn main() {} diff --git a/src/test/ui/issues/issue-58857.stderr b/src/test/ui/issues/issue-58857.stderr index ab9a0130c00b0..9bc80cc270b0f 100644 --- a/src/test/ui/issues/issue-58857.stderr +++ b/src/test/ui/issues/issue-58857.stderr @@ -1,10 +1,10 @@ -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-58857.rs:4:7 | LL | impl Conj{} - | ^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^ negative bounds are not supported | - = help: remove the trait bound + = help: remove the bound error: aborting due to previous error diff --git a/src/test/ui/parser/issue-33418.fixed b/src/test/ui/parser/issue-33418.fixed index 2aaa3b5b1ea50..ed885ae143566 100644 --- a/src/test/ui/parser/issue-33418.fixed +++ b/src/test/ui/parser/issue-33418.fixed @@ -1,15 +1,15 @@ // run-rustfix trait Tr {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr2: SuperA {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr3: SuperB {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr4: SuperB + SuperD {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr5 {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait SuperA {} trait SuperB {} diff --git a/src/test/ui/parser/issue-33418.rs b/src/test/ui/parser/issue-33418.rs index 5533152092719..9934284abfbbe 100644 --- a/src/test/ui/parser/issue-33418.rs +++ b/src/test/ui/parser/issue-33418.rs @@ -1,17 +1,17 @@ // run-rustfix trait Tr: !SuperA {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr2: SuperA + !SuperB {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr3: !SuperA + SuperB {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr4: !SuperA + SuperB + !SuperC + SuperD {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait Tr5: !SuperA + !SuperB {} -//~^ ERROR negative trait bounds are not supported +//~^ ERROR negative bounds are not supported trait SuperA {} trait SuperB {} diff --git a/src/test/ui/parser/issue-33418.stderr b/src/test/ui/parser/issue-33418.stderr index 479e7bed1016a..7f361dbe2718f 100644 --- a/src/test/ui/parser/issue-33418.stderr +++ b/src/test/ui/parser/issue-33418.stderr @@ -1,46 +1,46 @@ -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:3:9 | LL | trait Tr: !SuperA {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bound + = help: remove the bound -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:5:19 | LL | trait Tr2: SuperA + !SuperB {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bound + = help: remove the bound -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:7:10 | LL | trait Tr3: !SuperA + SuperB {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bound + = help: remove the bound -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:9:10 | LL | trait Tr4: !SuperA + SuperB | ^^^^^^^^^ LL | + !SuperC + SuperD {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bounds + = help: remove the bounds -error: negative trait bounds are not supported +error: negative bounds are not supported --> $DIR/issue-33418.rs:12:10 | LL | trait Tr5: !SuperA | ^^^^^^^^^ LL | + !SuperB {} - | ^^^^^^^^^ negative trait bounds are not supported + | ^^^^^^^^^ negative bounds are not supported | - = help: remove the trait bounds + = help: remove the bounds error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.rs b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.rs new file mode 100644 index 0000000000000..5a109ba7c6894 --- /dev/null +++ b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.rs @@ -0,0 +1,12 @@ +// In this regression test for #67146, we check that the +// negative outlives bound `!'a` is rejected by the parser. +// This regression was first introduced in PR #57364. + +fn main() {} + +fn f1() {} +//~^ ERROR negative bounds are not supported +fn f2<'a, T: Ord + !'a>() {} +//~^ ERROR negative bounds are not supported +fn f3<'a, T: !'a + Ord>() {} +//~^ ERROR negative bounds are not supported diff --git a/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr new file mode 100644 index 0000000000000..74437c1a0081a --- /dev/null +++ b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr @@ -0,0 +1,26 @@ +error: negative bounds are not supported + --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:7:8 + | +LL | fn f1() {} + | ^^^^^^^^^^ negative bounds are not supported + | + = help: remove the bound + +error: negative bounds are not supported + --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:18 + | +LL | fn f2<'a, T: Ord + !'a>() {} + | ^^^^^ negative bounds are not supported + | + = help: remove the bound + +error: negative bounds are not supported + --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:11:12 + | +LL | fn f3<'a, T: !'a + Ord>() {} + | ^^^^^ negative bounds are not supported + | + = help: remove the bound + +error: aborting due to 3 previous errors + From f221b394def7e739c6c2b936afd12e032ee0f827 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 12:29:05 +0100 Subject: [PATCH 24/28] extract error_negative_bounds --- src/librustc_parse/parser/ty.rs | 62 +++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index db9a0ada525b1..3877f3f9a62f6 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -371,33 +371,7 @@ impl<'a> Parser<'a> { } if !negative_bounds.is_empty() { - let negative_bounds_len = negative_bounds.len(); - let last_span = *negative_bounds.last().unwrap(); - let mut err = self.struct_span_err( - negative_bounds, - "negative bounds are not supported", - ); - err.span_label(last_span, "negative bounds are not supported"); - if let Some(bound_list) = colon_span { - let bound_list = bound_list.to(self.prev_span); - let mut new_bound_list = String::new(); - if !bounds.is_empty() { - let mut snippets = bounds.iter().map(|bound| bound.span()) - .map(|span| self.span_to_snippet(span)); - while let Some(Ok(snippet)) = snippets.next() { - new_bound_list.push_str(" + "); - new_bound_list.push_str(&snippet); - } - new_bound_list = new_bound_list.replacen(" +", ":", 1); - } - err.span_suggestion_hidden( - bound_list, - &format!("remove the bound{}", pluralize!(negative_bounds_len)), - new_bound_list, - Applicability::MachineApplicable, - ); - } - err.emit(); + self.error_negative_bounds(colon_span, &bounds, negative_bounds); } Ok(bounds) @@ -414,6 +388,40 @@ impl<'a> Parser<'a> { || self.check(&token::OpenDelim(token::Paren)) } + fn error_negative_bounds( + &self, + colon_span: Option, + bounds: &[GenericBound], + negative_bounds: Vec, + ) { + let negative_bounds_len = negative_bounds.len(); + let last_span = *negative_bounds.last().unwrap(); + let mut err = self.struct_span_err( + negative_bounds, + "negative bounds are not supported", + ); + err.span_label(last_span, "negative bounds are not supported"); + if let Some(bound_list) = colon_span { + let bound_list = bound_list.to(self.prev_span); + let mut new_bound_list = String::new(); + if !bounds.is_empty() { + let mut snippets = bounds.iter().map(|bound| self.span_to_snippet(bound.span())); + while let Some(Ok(snippet)) = snippets.next() { + new_bound_list.push_str(" + "); + new_bound_list.push_str(&snippet); + } + new_bound_list = new_bound_list.replacen(" +", ":", 1); + } + err.span_suggestion_hidden( + bound_list, + &format!("remove the bound{}", pluralize!(negative_bounds_len)), + new_bound_list, + Applicability::MachineApplicable, + ); + } + err.emit(); + } + /// Parses a bound according to the grammar: /// ``` /// BOUND = TY_BOUND | LT_BOUND From d0105600d191996ae60bec2a2ecec2485b02722a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 12:29:55 +0100 Subject: [PATCH 25/28] document parse_late_bound_lifetime_defs --- src/librustc_parse/parser/ty.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 3877f3f9a62f6..09697c01a54b1 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -514,6 +514,7 @@ impl<'a> Parser<'a> { Ok(GenericBound::Trait(poly_trait, modifier)) } + /// Optionally parses `for<$generic_params>`. pub(super) fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec> { if self.eat_keyword(kw::For) { self.expect_lt()?; From d6f37c66c72ed4692781250165bf5fd56a64dfaa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 8 Dec 2019 12:40:20 +0100 Subject: [PATCH 26/28] parse_ty_bare_fn: improve docs --- src/librustc_parse/parser/ty.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 09697c01a54b1..15e0d54bb0171 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -250,20 +250,15 @@ impl<'a> Parser<'a> { self.check_keyword(kw::Extern) } - /// Parses a `TyKind::BareFn` type. + /// Parses a function pointer type (`TyKind::BareFn`). + /// ``` + /// [unsafe] [extern "ABI"] fn (S) -> T + /// ^~~~~^ ^~~~^ ^~^ ^ + /// | | | | + /// | | | Return type + /// Function Style ABI Parameter types + /// ``` fn parse_ty_bare_fn(&mut self, generic_params: Vec) -> PResult<'a, TyKind> { - /* - - [unsafe] [extern "ABI"] fn (S) -> T - ^~~~^ ^~~~^ ^~^ ^ - | | | | - | | | Return type - | | Argument types - | | - | ABI - Function Style - */ - let unsafety = self.parse_unsafety(); let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; From 52fa020bbf030ae2a57e66bb259ee626a5f1132e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Dec 2019 03:28:22 +0100 Subject: [PATCH 27/28] unwrap -> expect --- src/librustc_parse/parser/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 15e0d54bb0171..b83ec71124def 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -390,7 +390,7 @@ impl<'a> Parser<'a> { negative_bounds: Vec, ) { let negative_bounds_len = negative_bounds.len(); - let last_span = *negative_bounds.last().unwrap(); + let last_span = *negative_bounds.last().expect("no negative bounds, but still error?"); let mut err = self.struct_span_err( negative_bounds, "negative bounds are not supported", From db4818f3253254bafac707d58ec3d13def0e6f86 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 21 Dec 2019 03:32:54 +0100 Subject: [PATCH 28/28] span_suggestion_hidden -> tool_only_span_suggestion --- src/librustc_parse/parser/ty.rs | 2 +- src/test/ui/issues/issue-58857.stderr | 2 -- src/test/ui/parser/issue-33418.stderr | 10 ---------- ...67146-negative-outlives-bound-syntactic-fail.stderr | 6 ------ 4 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index b83ec71124def..9f5fd6d0a36eb 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -407,7 +407,7 @@ impl<'a> Parser<'a> { } new_bound_list = new_bound_list.replacen(" +", ":", 1); } - err.span_suggestion_hidden( + err.tool_only_span_suggestion( bound_list, &format!("remove the bound{}", pluralize!(negative_bounds_len)), new_bound_list, diff --git a/src/test/ui/issues/issue-58857.stderr b/src/test/ui/issues/issue-58857.stderr index 9bc80cc270b0f..e2acec47e5abf 100644 --- a/src/test/ui/issues/issue-58857.stderr +++ b/src/test/ui/issues/issue-58857.stderr @@ -3,8 +3,6 @@ error: negative bounds are not supported | LL | impl Conj{} | ^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: aborting due to previous error diff --git a/src/test/ui/parser/issue-33418.stderr b/src/test/ui/parser/issue-33418.stderr index 7f361dbe2718f..9a8733e89292e 100644 --- a/src/test/ui/parser/issue-33418.stderr +++ b/src/test/ui/parser/issue-33418.stderr @@ -3,24 +3,18 @@ error: negative bounds are not supported | LL | trait Tr: !SuperA {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-33418.rs:5:19 | LL | trait Tr2: SuperA + !SuperB {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-33418.rs:7:10 | LL | trait Tr3: !SuperA + SuperB {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-33418.rs:9:10 @@ -29,8 +23,6 @@ LL | trait Tr4: !SuperA + SuperB | ^^^^^^^^^ LL | + !SuperC + SuperD {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bounds error: negative bounds are not supported --> $DIR/issue-33418.rs:12:10 @@ -39,8 +31,6 @@ LL | trait Tr5: !SuperA | ^^^^^^^^^ LL | + !SuperB {} | ^^^^^^^^^ negative bounds are not supported - | - = help: remove the bounds error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr index 74437c1a0081a..4dc0634730442 100644 --- a/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr +++ b/src/test/ui/parser/issue-67146-negative-outlives-bound-syntactic-fail.stderr @@ -3,24 +3,18 @@ error: negative bounds are not supported | LL | fn f1() {} | ^^^^^^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:18 | LL | fn f2<'a, T: Ord + !'a>() {} | ^^^^^ negative bounds are not supported - | - = help: remove the bound error: negative bounds are not supported --> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:11:12 | LL | fn f3<'a, T: !'a + Ord>() {} | ^^^^^ negative bounds are not supported - | - = help: remove the bound error: aborting due to 3 previous errors