diff --git a/src/ast/item.rs b/src/ast/item.rs index 65703bb..2677108 100644 --- a/src/ast/item.rs +++ b/src/ast/item.rs @@ -39,12 +39,20 @@ pub(crate) enum ItemKind<'src> { #[derive(Debug)] pub(crate) struct ConstItem<'src> { pub(crate) defaultness: Defaultness, + pub(crate) tyness: Tyness, pub(crate) binder: Ident<'src>, pub(crate) generics: Generics<'src>, pub(crate) ty: Ty<'src>, pub(crate) body: Option>, } +// FIXME: horrible name +#[derive(Debug)] +pub(crate) enum Tyness { + Ty, + Not, +} + #[derive(Debug)] pub(crate) struct ConstBlockItem<'src> { pub(crate) body: BlockExpr<'src>, diff --git a/src/fmter/item.rs b/src/fmter/item.rs index 057e1e6..7c4247e 100644 --- a/src/fmter/item.rs +++ b/src/fmter/item.rs @@ -60,9 +60,13 @@ impl Fmt for (ast::ItemKind<'_>, Vec>) { impl Fmt for ast::ConstItem<'_> { fn fmt(self, cx: &mut Cx<'_>) { - let Self { defaultness, binder, generics, ty, body } = self; + let Self { defaultness, tyness, binder, generics, ty, body } = self; defaultness.trailing_space().fmt(cx); + match tyness { + ast::Tyness::Ty => fmt!(cx, "type "), + ast::Tyness::Not => {} + } fmt!(cx, "const {binder}"); if !generics.params.is_empty() { generics.params.fmt(cx); diff --git a/src/parser/item.rs b/src/parser/item.rs index 6ea86d9..07c28f3 100644 --- a/src/parser/item.rs +++ b/src/parser/item.rs @@ -90,7 +90,6 @@ impl<'src> Parser<'_, '_, 'src> { | TokenKind::Macro | TokenKind::Struct | TokenKind::Trait - | TokenKind::Type | TokenKind::Use => return true, TokenKind::CommonIdent => match self.source(self.token.span) { weak::Union::STR => return weak::Union.qualifies(self), @@ -146,13 +145,22 @@ impl<'src> Parser<'_, '_, 'src> { // FIXME: Provide more targeted diagnostics if the qualifiers don't make sense. match qualifiers.as_slice() { [] => {} - [Qualifier::Const] => { - return if self.consume(TokenKind::OpenCurlyBracket) { - // FEATURE: `const_block_items` - self.fin_parse_const_block_item() - } else { - self.fin_parse_const_item(defaultness) + [Qualifier::Type] => return self.fin_parse_ty_alias_item(defaultness), + // FEATURE: `const_block_items` + [Qualifier::Const] if self.consume(TokenKind::OpenCurlyBracket) => { + return self.fin_parse_const_block_item(); + } + [qualifiers @ .., Qualifier::Const] => { + // FEATURE: `min_generic_const_args` + let (tyness, qualifiers) = match qualifiers { + [Qualifier::Type, qualifiers @ ..] => (ast::Tyness::Ty, qualifiers), + _ => (ast::Tyness::Not, qualifiers), }; + if !qualifiers.is_empty() { + return self.fatal(Error::InvalidItemPrefix(start.until(self.token.span))); + } + + return self.fin_parse_const_item(defaultness, tyness); } // `crate` can't be a qualifier itself because it may also begin paths & it's not worth the look-ahead. [Qualifier::Extern(None)] if self.consume(TokenKind::Crate) => { @@ -265,10 +273,6 @@ impl<'src> Parser<'_, '_, 'src> { self.advance(); return self.fin_parse_struct_item(); } - TokenKind::Type => { - self.advance(); - return self.fin_parse_ty_alias_item(defaultness); - } TokenKind::Use => { self.advance(); return self.fin_parse_use_item(); @@ -333,6 +337,7 @@ impl<'src> Parser<'_, '_, 'src> { TokenKind::Mod => Qualifier::Mod, TokenKind::Static => Qualifier::Static, TokenKind::Trait => Qualifier::Trait, + TokenKind::Type => Qualifier::Type, TokenKind::Unsafe if self.peek(1).kind != TokenKind::OpenCurlyBracket => { Qualifier::Unsafe } @@ -359,6 +364,7 @@ impl<'src> Parser<'_, '_, 'src> { fn fin_parse_const_item( &mut self, defaultness: ast::Defaultness, + tyness: ast::Tyness, ) -> Result> { let (binder, _) = self.parse_common_ident_or(TokenKind::Underscore)?; // FEATURE: `generic_const_items` @@ -371,6 +377,7 @@ impl<'src> Parser<'_, '_, 'src> { Ok(ast::ItemKind::Const(Box::new(ast::ConstItem { defaultness, + tyness, binder, generics: ast::Generics { params, preds }, ty, @@ -1101,6 +1108,7 @@ enum Qualifier<'src> { Safe, Static, Trait, + Type, Unsafe, } diff --git a/src/parser/path.rs b/src/parser/path.rs index 99d26a5..d9fd34c 100644 --- a/src/parser/path.rs +++ b/src/parser/path.rs @@ -219,6 +219,7 @@ impl<'src> Parser<'_, '_, 'src> { self.advance(); Ok(ast::ExprKind::Path(Box::new(ast::ExtPath::ident(ident))).into()) } + // FEATURE: `min_generic_const_args` TokenKind::Const => { self.advance(); let block = self.parse_block_expr()?; @@ -237,6 +238,7 @@ impl<'src> Parser<'_, '_, 'src> { fn begins_const_arg(&self) -> bool { // NOTE: To be kept in sync with `Self::parse_const_arg`. + // Re. `const`, FEATURE: `min_generic_const_args` matches!(self.token.kind, TokenKind::OpenCurlyBracket | TokenKind::Const) || self.begins_negatable_lit() }