Skip to content

Commit

Permalink
parser: Allow mut occurrence only in path pattern (#990)
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Nak authored Feb 28, 2024
1 parent 8fe6cf3 commit 65f3804
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 24 deletions.
23 changes: 19 additions & 4 deletions crates/hir/src/hir_def/pat.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use cranelift_entity::entity_impl;

use crate::{span::pat::LazyPatSpan, HirDb};

use super::{Body, IdentId, LitKind, Partial, PathId};
use crate::{span::pat::LazyPatSpan, HirDb};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Pat {
WildCard,
Rest,
Lit(Partial<LitKind>),
Tuple(Vec<PatId>),
Path(Partial<PathId>),
/// The second bool is `true` if the pat has `mut` in front of it.
Path(Partial<PathId>, bool),
PathTuple(Partial<PathId>, Vec<PatId>),
Record(Partial<PathId>, Vec<RecordPatField>),
Or(PatId, PatId),
Expand All @@ -20,7 +20,7 @@ impl Pat {
/// Return `true` if this pattern is a binding.
pub fn is_bind(&self, db: &dyn HirDb) -> bool {
match self {
Self::Path(Partial::Present(p)) => p.len(db) == 1,
Self::Path(Partial::Present(p), _) => p.len(db) == 1,
_ => false,
}
}
Expand Down Expand Up @@ -53,3 +53,18 @@ pub struct RecordPatField {
pub label: Partial<IdentId>,
pub pat: PatId,
}

impl RecordPatField {
pub fn label(&self, db: &dyn HirDb, body: Body) -> Option<IdentId> {
if let Partial::Present(label) = self.label {
return Some(label);
}

match self.pat.data(db, body) {
Partial::Present(Pat::Path(Partial::Present(path), _)) if path.is_ident(db) => {
path.last_segment(db).to_opt()
}
_ => None,
}
}
}
7 changes: 5 additions & 2 deletions crates/hir/src/hir_def/path.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{hir_def::Partial, HirDb};

use super::{kw, IdentId};
use crate::{hir_def::Partial, HirDb};

#[salsa::interned]
pub struct PathId {
Expand All @@ -17,6 +16,10 @@ impl PathId {
self.segments(db).len()
}

pub fn is_ident(self, db: &dyn HirDb) -> bool {
self.len(db) == 1
}

pub fn self_ty(db: &dyn HirDb) -> Self {
let self_ty = Partial::Present(kw::SELF_TY);
Self::new(db, vec![self_ty])
Expand Down
9 changes: 4 additions & 5 deletions crates/hir/src/lower/pat.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use parser::ast;

use super::body::BodyCtxt;
use crate::{
hir_def::{pat::*, IdentId, LitKind, PathId},
span::HirOrigin,
};

use super::body::BodyCtxt;

impl Pat {
pub(super) fn lower_ast(ctxt: &mut BodyCtxt<'_, '_>, ast: ast::Pat) -> PatId {
let pat = match &ast.kind() {
Expand All @@ -30,9 +29,9 @@ impl Pat {
Pat::Tuple(elems)
}

ast::PatKind::Path(path) => {
let path = PathId::lower_ast_partial(ctxt.f_ctxt, path.path());
Pat::Path(path)
ast::PatKind::Path(path_ast) => {
let path = PathId::lower_ast_partial(ctxt.f_ctxt, path_ast.path());
Pat::Path(path, path_ast.mut_token().is_some())
}

ast::PatKind::PathTuple(path_tup) => {
Expand Down
4 changes: 4 additions & 0 deletions crates/hir/src/span/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ define_lazy_span_node!(
define_lazy_span_node!(
LazyPathPatSpan,
ast::PathPat,
@token {
(mut_token, mut_token),
}

@node {
(path, path, LazyPathSpan),
}
Expand Down
2 changes: 1 addition & 1 deletion crates/hir/src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ where
}
}

Pat::Path(path) => {
Pat::Path(path, _) => {
if let Some(path) = path.to_opt() {
ctxt.with_new_ctxt(
|span| span.into_path_pat().path_moved(),
Expand Down
19 changes: 11 additions & 8 deletions crates/parser2/src/ast/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ impl Pat {
_ => unreachable!(),
}
}

/// Returns the `mut` keyword if the patter is mutable.
pub fn mut_token(&self) -> Option<SyntaxToken> {
support::token(self.syntax(), SK::MutKw)
}
}

ast_node! {
Expand Down Expand Up @@ -91,6 +86,11 @@ impl PathPat {
pub fn path(&self) -> Option<super::Path> {
support::child(self.syntax())
}

/// Returns the `mut` keyword if the patter is mutable.
pub fn mut_token(&self) -> Option<SyntaxToken> {
support::token(self.syntax(), SK::MutKw)
}
}

ast_node! {
Expand Down Expand Up @@ -175,11 +175,10 @@ pub enum PatKind {

#[cfg(test)]
mod tests {
use crate::{lexer::Lexer, parser::Parser};

use wasm_bindgen_test::wasm_bindgen_test;

use super::*;
use crate::{lexer::Lexer, parser::Parser};

fn parse_pat<T>(source: &str) -> T
where
Expand Down Expand Up @@ -282,9 +281,13 @@ mod tests {
assert!(matches!(field.pat().unwrap().kind(), PatKind::Path(_)));
}
2 => {
let PatKind::Path(pat) = field.pat().unwrap().kind() else {
panic!("unexpected record pat");
};

assert!(field.name().is_none());
assert!(matches!(field.pat().unwrap().kind(), PatKind::Path(_)));
assert!(field.pat().unwrap().mut_token().is_some());
assert!(pat.mut_token().is_some());
}
_ => panic!("unexpected record pat"),
}
Expand Down
31 changes: 27 additions & 4 deletions crates/parser2/src/parser/pat.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,38 @@
use super::{define_scope, path::PathScope, token_stream::TokenStream, Parser};
use crate::{
parser::lit::{is_lit, LitScope},
parser::{
lit::{is_lit, LitScope},
token_stream::LexicalToken,
},
SyntaxKind,
};

use super::{define_scope, path::PathScope, token_stream::TokenStream, Parser};

pub fn parse_pat<S: TokenStream>(parser: &mut Parser<S>) -> bool {
use SyntaxKind::*;
parser.bump_trivias();
let checkpoint = parser.checkpoint();
parser.bump_if(SyntaxKind::MutKw);
let has_mut = parser.bump_if(SyntaxKind::MutKw);

let token = parser.current_token();
if has_mut {
match token.as_ref().map(|t| t.syntax_kind()) {
Some(Underscore | Dot2 | LParen) => {
parser.error_msg_on_current_token(&format!(
"`mut` is not allowed on `{}`",
token.unwrap().text()
));
}

Some(kind) if is_lit(kind) => {
parser.error_msg_on_current_token(&format!(
"`mut` is not allowed on `{}`",
token.unwrap().text()
));
}

_ => {}
}
}

let success = match parser.current_kind() {
Some(Underscore) => parser.parse(WildCardPatScope::default(), Some(checkpoint)),
Expand Down

0 comments on commit 65f3804

Please sign in to comment.