From 8cdfd091983748f53563dd29f55ec9ef7f7f5670 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 3 Sep 2023 09:57:10 -0700 Subject: [PATCH] Parse const item with generics as Verbatim --- src/item.rs | 116 +++++++++++++++++++++++---------------- tests/test_precedence.rs | 44 +++++++++++++-- 2 files changed, 108 insertions(+), 52 deletions(-) diff --git a/src/item.rs b/src/item.rs index 6efde57852..ee91f5914c 100644 --- a/src/item.rs +++ b/src/item.rs @@ -996,21 +996,24 @@ pub(crate) mod parsing { }; generics.where_clause = input.parse()?; let semi_token: Token![;] = input.parse()?; - if let Some((eq_token, expr)) = value { - Ok(Item::Const(ItemConst { - attrs: Vec::new(), - vis, - const_token, - ident, - generics, - colon_token, - ty, - eq_token, - expr: Box::new(expr), - semi_token, - })) - } else { - Ok(Item::Verbatim(verbatim::between(&begin, input))) + match value { + Some((eq_token, expr)) + if generics.lt_token.is_none() && generics.where_clause.is_none() => + { + Ok(Item::Const(ItemConst { + attrs: Vec::new(), + vis, + const_token, + ident, + generics, + colon_token, + ty, + eq_token, + expr: Box::new(expr), + semi_token, + })) + } + _ => Ok(Item::Verbatim(verbatim::between(&begin, input))), } } else if lookahead.peek(Token![unsafe]) { ahead.parse::()?; @@ -1419,12 +1422,10 @@ pub(crate) mod parsing { return Err(lookahead.error()); }; - let mut generics: Generics = input.parse()?; let colon_token: Token![:] = input.parse()?; let ty: Type = input.parse()?; let eq_token: Token![=] = input.parse()?; let expr: Expr = input.parse()?; - generics.where_clause = input.parse()?; let semi_token: Token![;] = input.parse()?; Ok(ItemConst { @@ -1432,7 +1433,7 @@ pub(crate) mod parsing { vis, const_token, ident, - generics, + generics: Generics::default(), colon_token, ty: Box::new(ty), eq_token, @@ -2244,10 +2245,36 @@ pub(crate) mod parsing { let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead) { input.parse().map(TraitItem::Fn) } else if lookahead.peek(Token![const]) { - ahead.parse::()?; + let const_token: Token![const] = ahead.parse()?; let lookahead = ahead.lookahead1(); if lookahead.peek(Ident) || lookahead.peek(Token![_]) { - input.parse().map(TraitItem::Const) + input.advance_to(&ahead); + let ident = input.call(Ident::parse_any)?; + let mut generics: Generics = input.parse()?; + let colon_token: Token![:] = input.parse()?; + let ty: Type = input.parse()?; + let default = if let Some(eq_token) = input.parse::>()? { + let expr: Expr = input.parse()?; + Some((eq_token, expr)) + } else { + None + }; + generics.where_clause = input.parse()?; + let semi_token: Token![;] = input.parse()?; + if generics.lt_token.is_none() && generics.where_clause.is_none() { + Ok(TraitItem::Const(TraitItemConst { + attrs: Vec::new(), + const_token, + ident, + generics, + colon_token, + ty, + default, + semi_token, + })) + } else { + return Ok(TraitItem::Verbatim(verbatim::between(&begin, input))); + } } else if lookahead.peek(Token![async]) || lookahead.peek(Token![unsafe]) || lookahead.peek(Token![extern]) @@ -2303,7 +2330,6 @@ pub(crate) mod parsing { return Err(lookahead.error()); }; - let mut generics: Generics = input.parse()?; let colon_token: Token![:] = input.parse()?; let ty: Type = input.parse()?; let default = if input.peek(Token![=]) { @@ -2313,14 +2339,13 @@ pub(crate) mod parsing { } else { None }; - generics.where_clause = input.parse()?; let semi_token: Token![;] = input.parse()?; Ok(TraitItemConst { attrs, const_token, ident, - generics, + generics: Generics::default(), colon_token, ty, default, @@ -2589,22 +2614,25 @@ pub(crate) mod parsing { }; generics.where_clause = input.parse()?; let semi_token: Token![;] = input.parse()?; - return if let Some((eq_token, expr)) = value { - Ok(ImplItem::Const(ImplItemConst { - attrs, - vis, - defaultness, - const_token, - ident, - generics, - colon_token, - ty, - eq_token, - expr, - semi_token, - })) - } else { - Ok(ImplItem::Verbatim(verbatim::between(&begin, input))) + return match value { + Some((eq_token, expr)) + if generics.lt_token.is_none() && generics.where_clause.is_none() => + { + Ok(ImplItem::Const(ImplItemConst { + attrs, + vis, + defaultness, + const_token, + ident, + generics, + colon_token, + ty, + eq_token, + expr, + semi_token, + })) + } + _ => Ok(ImplItem::Verbatim(verbatim::between(&begin, input))), }; } else if lookahead.peek(Token![type]) { parse_impl_item_type(begin, input) @@ -2652,12 +2680,10 @@ pub(crate) mod parsing { return Err(lookahead.error()); }; - let mut generics: Generics = input.parse()?; let colon_token: Token![:] = input.parse()?; let ty: Type = input.parse()?; let eq_token: Token![=] = input.parse()?; let expr: Expr = input.parse()?; - generics.where_clause = input.parse()?; let semi_token: Token![;] = input.parse()?; Ok(ImplItemConst { @@ -2666,7 +2692,7 @@ pub(crate) mod parsing { defaultness, const_token, ident, - generics, + generics: Generics::default(), colon_token, ty, eq_token, @@ -2883,12 +2909,10 @@ mod printing { self.vis.to_tokens(tokens); self.const_token.to_tokens(tokens); self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); self.colon_token.to_tokens(tokens); self.ty.to_tokens(tokens); self.eq_token.to_tokens(tokens); self.expr.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); self.semi_token.to_tokens(tokens); } } @@ -3135,14 +3159,12 @@ mod printing { tokens.append_all(self.attrs.outer()); self.const_token.to_tokens(tokens); self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); self.colon_token.to_tokens(tokens); self.ty.to_tokens(tokens); if let Some((eq_token, default)) = &self.default { eq_token.to_tokens(tokens); default.to_tokens(tokens); } - self.generics.where_clause.to_tokens(tokens); self.semi_token.to_tokens(tokens); } } @@ -3203,12 +3225,10 @@ mod printing { self.defaultness.to_tokens(tokens); self.const_token.to_tokens(tokens); self.ident.to_tokens(tokens); - self.generics.to_tokens(tokens); self.colon_token.to_tokens(tokens); self.ty.to_tokens(tokens); self.eq_token.to_tokens(tokens); self.expr.to_tokens(tokens); - self.generics.where_clause.to_tokens(tokens); self.semi_token.to_tokens(tokens); } } diff --git a/tests/test_precedence.rs b/tests/test_precedence.rs index b49577f0f3..e729ae195a 100644 --- a/tests/test_precedence.rs +++ b/tests/test_precedence.rs @@ -30,6 +30,7 @@ extern crate rustc_ast_pretty; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_span; +extern crate smallvec; extern crate thin_vec; use crate::common::eq::SpanlessEq; @@ -168,15 +169,17 @@ fn librustc_parse_and_rewrite(input: &str) -> Option> { /// This method operates on librustc objects. fn librustc_brackets(mut librustc_expr: P) -> Option> { use rustc_ast::ast::{ - Attribute, BinOpKind, Block, BorrowKind, Expr, ExprField, ExprKind, GenericArg, - GenericBound, Local, LocalKind, Pat, Stmt, StmtKind, StructExpr, StructRest, - TraitBoundModifier, Ty, + AssocItem, AssocItemKind, Attribute, BinOpKind, Block, BorrowKind, Expr, ExprField, + ExprKind, GenericArg, GenericBound, ItemKind, Local, LocalKind, Pat, Stmt, StmtKind, + StructExpr, StructRest, TraitBoundModifier, Ty, }; use rustc_ast::mut_visit::{ - noop_visit_generic_arg, noop_visit_local, noop_visit_param_bound, MutVisitor, + noop_flat_map_assoc_item, noop_visit_generic_arg, noop_visit_item_kind, noop_visit_local, + noop_visit_param_bound, MutVisitor, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_span::DUMMY_SP; + use smallvec::SmallVec; use std::mem; use std::ops::DerefMut; use thin_vec::ThinVec; @@ -300,6 +303,39 @@ fn librustc_brackets(mut librustc_expr: P) -> Option> { } } + fn visit_item_kind(&mut self, item: &mut ItemKind) { + match item { + ItemKind::Const(const_item) + if !const_item.generics.params.is_empty() + || !const_item.generics.where_clause.predicates.is_empty() => {} + _ => noop_visit_item_kind(item, self), + } + } + + fn flat_map_trait_item(&mut self, item: P) -> SmallVec<[P; 1]> { + match &item.kind { + AssocItemKind::Const(const_item) + if !const_item.generics.params.is_empty() + || !const_item.generics.where_clause.predicates.is_empty() => + { + SmallVec::from([item]) + } + _ => noop_flat_map_assoc_item(item, self), + } + } + + fn flat_map_impl_item(&mut self, item: P) -> SmallVec<[P; 1]> { + match &item.kind { + AssocItemKind::Const(const_item) + if !const_item.generics.params.is_empty() + || !const_item.generics.where_clause.predicates.is_empty() => + { + SmallVec::from([item]) + } + _ => noop_flat_map_assoc_item(item, self), + } + } + // We don't want to look at expressions that might appear in patterns or // types yet. We'll look into comparing those in the future. For now // focus on expressions appearing in other places.