From 37cbc751e4c13bfa0d1a21dedf5d2ac6e0cc2e5f Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Tue, 17 Mar 2026 10:54:13 +0200 Subject: [PATCH 1/2] change Identifier to Pattern in `MatchPattern` --- src/ast.rs | 14 ++++++++++---- src/compile/mod.rs | 8 ++++---- src/parse.rs | 32 ++++++++++++++++---------------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 3c59f2f7..20dd2a70 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1400,16 +1400,22 @@ impl AbstractSyntaxTree for Match { Expression::analyze(from.scrutinee(), &scrutinee_ty, scope).map(Arc::new)?; scope.push_scope(); - if let Some((id_l, ty_l)) = from.left().pattern().as_typed_variable() { + if let Some((pat_l, ty_l)) = from.left().pattern().as_typed_pattern() { let ty_l = scope.resolve(ty_l).with_span(from)?; - scope.insert_variable(id_l.clone(), ty_l); + let typed_variables = pat_l.is_of_type(&ty_l).with_span(from)?; + for (identifier, ty) in typed_variables { + scope.insert_variable(identifier, ty); + } } let ast_l = Expression::analyze(from.left().expression(), ty, scope).map(Arc::new)?; scope.pop_scope(); scope.push_scope(); - if let Some((id_r, ty_r)) = from.right().pattern().as_typed_variable() { + if let Some((pat_r, ty_r)) = from.right().pattern().as_typed_pattern() { let ty_r = scope.resolve(ty_r).with_span(from)?; - scope.insert_variable(id_r.clone(), ty_r); + let typed_variables = pat_r.is_of_type(&ty_r).with_span(from)?; + for (identifier, ty) in typed_variables { + scope.insert_variable(identifier, ty); + } } let ast_r = Expression::analyze(from.right().expression(), ty, scope).map(Arc::new)?; scope.pop_scope(); diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 2af17e6f..9f8dffb4 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -656,9 +656,9 @@ impl Match { scope.insert( self.left() .pattern() - .as_variable() + .as_pattern() .cloned() - .map_or(Pattern::Ignore, Pattern::Identifier), + .unwrap_or(Pattern::Ignore), ); let left = self.left().expression().compile(scope)?; scope.pop_scope(); @@ -667,9 +667,9 @@ impl Match { scope.insert( self.right() .pattern() - .as_variable() + .as_pattern() .cloned() - .map_or(Pattern::Ignore, Pattern::Identifier), + .unwrap_or(Pattern::Ignore), ); let right = self.right().expression().compile(scope)?; scope.pop_scope(); diff --git a/src/parse.rs b/src/parse.rs index c42c6f3d..50b10883 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -429,14 +429,14 @@ impl MatchArm { #[derive(Clone, Debug, Eq, PartialEq, Hash)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub enum MatchPattern { - /// Bind inner value of left value to variable name. - Left(Identifier, AliasedType), - /// Bind inner value of right value to variable name. - Right(Identifier, AliasedType), + /// Bind inner value of left value to a pattern. + Left(Pattern, AliasedType), + /// Bind inner value of right value to a pattern. + Right(Pattern, AliasedType), /// Match none value (no binding). None, - /// Bind inner value of some value to variable name. - Some(Identifier, AliasedType), + /// Bind inner value of some value to a pattern. + Some(Pattern, AliasedType), /// Match false value (no binding). False, /// Match true value (no binding). @@ -444,8 +444,8 @@ pub enum MatchPattern { } impl MatchPattern { - /// Access the identifier of a pattern that binds a variable. - pub fn as_variable(&self) -> Option<&Identifier> { + /// Access the pattern of a match pattern that binds a variables. + pub fn as_pattern(&self) -> Option<&Pattern> { match self { MatchPattern::Left(i, _) | MatchPattern::Right(i, _) | MatchPattern::Some(i, _) => { Some(i) @@ -454,8 +454,8 @@ impl MatchPattern { } } - /// Access the identifier and the type of a pattern that binds a variable. - pub fn as_typed_variable(&self) -> Option<(&Identifier, &AliasedType)> { + /// Access the pattern and the type of a match pattern that binds a variables. + pub fn as_typed_pattern(&self) -> Option<(&Pattern, &AliasedType)> { match self { MatchPattern::Left(i, ty) | MatchPattern::Right(i, ty) | MatchPattern::Some(i, ty) => { Some((i, ty)) @@ -1623,17 +1623,17 @@ impl ChumskyParse for MatchPattern { where I: ValueInput<'tokens, Token = Token<'src>, Span = Span>, { - let wrapper = |name: &'static str, ctor: fn(Identifier, AliasedType) -> Self| { + let wrapper = |name: &'static str, ctor: fn(Pattern, AliasedType) -> Self| { select! { Token::Ident(i) if i == name => i } .ignore_then(delimited_with_recovery( - Identifier::parser() + Pattern::parser() .then_ignore(just(Token::Colon)) .then(AliasedType::parser()), Token::LParen, Token::RParen, |_| { ( - Identifier::from_str_unchecked(""), + Pattern::Ignore, AliasedType::alias(AliasName::from_str_unchecked("error")), ) }, @@ -2130,16 +2130,16 @@ impl crate::ArbitraryRec for Match { let scrutinee = Expression::arbitrary_rec(u, budget).map(Arc::new)?; let (pat_l, pat_r) = match u.int_in_range(0..=2)? { 0 => { - let id_l = Identifier::arbitrary(u)?; + let id_l = Pattern::arbitrary(u)?; let ty_l = AliasedType::arbitrary(u)?; let pat_l = MatchPattern::Left(id_l, ty_l); - let id_r = Identifier::arbitrary(u)?; + let id_r = Pattern::arbitrary(u)?; let ty_r = AliasedType::arbitrary(u)?; let pat_r = MatchPattern::Right(id_r, ty_r); (pat_l, pat_r) } 1 => { - let id_r = Identifier::arbitrary(u)?; + let id_r = Pattern::arbitrary(u)?; let ty_r = AliasedType::arbitrary(u)?; let pat_r = MatchPattern::Some(id_r, ty_r); (MatchPattern::None, pat_r) From 767c636d13c6c0071f6a5ee541bdb4b59a68bbb3 Mon Sep 17 00:00:00 2001 From: Volodymyr Herashchenko Date: Tue, 17 Mar 2026 10:56:48 +0200 Subject: [PATCH 2/2] add test for complex pattern matching in `match` --- examples/pattern_matching.simf | 15 +++++++++++++++ src/lib.rs | 7 +++++++ 2 files changed, 22 insertions(+) create mode 100644 examples/pattern_matching.simf diff --git a/examples/pattern_matching.simf b/examples/pattern_matching.simf new file mode 100644 index 00000000..706996fa --- /dev/null +++ b/examples/pattern_matching.simf @@ -0,0 +1,15 @@ +fn main() { + let complex_pattern: Either<(u32, u32, (u1, u1)), [u1; 8]> = Left((32, 3, (0, 1))); + + let a: u32 = match complex_pattern { + Left((a, b,(c, d)): (u32, u32, (u1, u1))) => { + assert!(jet::eq_32(b, 3)); + assert!(jet::eq_1(c, 0)); + assert!(jet::eq_1(d, 1)); + a + } + Right(_: [u1; 8]) => 0, + }; + + assert!(jet::eq_32(a, 32)); +} diff --git a/src/lib.rs b/src/lib.rs index b4a1032a..58083c06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -491,6 +491,13 @@ pub(crate) mod tests { .assert_run_success(); } + #[test] + fn pattern_matching() { + TestCase::program_file("./examples/pattern_matching.simf") + .with_witness_values(WitnessValues::default()) + .assert_run_success(); + } + #[test] #[cfg(feature = "serde")] fn sighash_non_interactive_fee_bump() {