@@ -23,7 +23,8 @@ macro_rules! match_error {
23
23
Some ( format!( "{}" , $e) )
24
24
} else {
25
25
None
26
- }
26
+ } ,
27
+ missing_semicolon: false ,
27
28
}
28
29
} } ;
29
30
( $fmt: expr, $( $arg: tt) +) => { {
@@ -32,7 +33,8 @@ macro_rules! match_error {
32
33
Some ( format!( $fmt, $( $arg) +) )
33
34
} else {
34
35
None
35
- }
36
+ } ,
37
+ missing_semicolon: false ,
36
38
}
37
39
} } ;
38
40
}
@@ -81,7 +83,9 @@ pub(crate) struct MatchFailureReason {
81
83
pub ( crate ) struct MatchFailed {
82
84
/// The reason why we failed to match. Only present when debug_active true in call to
83
85
/// `get_match`.
86
+ // FIXME: Turn this into an enum?
84
87
pub ( crate ) reason : Option < String > ,
88
+ pub ( crate ) missing_semicolon : bool ,
85
89
}
86
90
87
91
/// Checks if `code` matches the search pattern found in `search_scope`, returning information about
@@ -215,10 +219,29 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
215
219
}
216
220
SyntaxKind :: TOKEN_TREE => self . attempt_match_token_tree ( phase, pattern, code) ,
217
221
SyntaxKind :: PATH => self . attempt_match_path ( phase, pattern, code) ,
222
+ SyntaxKind :: LET_STMT => self . attempt_match_let ( phase, pattern, code) ,
218
223
_ => self . attempt_match_node_children ( phase, pattern, code) ,
219
224
}
220
225
}
221
226
227
+ fn attempt_match_let (
228
+ & self ,
229
+ phase : & mut Phase ,
230
+ pattern : & SyntaxNode ,
231
+ code : & SyntaxNode ,
232
+ ) -> Result < ( ) , MatchFailed > {
233
+ let pattern_it = PatternIterator :: new ( pattern) ;
234
+ let code_it = code. children_with_tokens ( ) ;
235
+
236
+ match self . attempt_match_sequences ( phase, pattern_it, code_it) {
237
+ // For now this error is only surfaced when the pattern is empty
238
+ Err ( MatchFailed { missing_semicolon : true , .. } ) /* if pattern_it.peek().is_none() */ => {
239
+ Ok ( ( ) )
240
+ }
241
+ res => res,
242
+ }
243
+ }
244
+
222
245
fn attempt_match_node_children (
223
246
& self ,
224
247
phase : & mut Phase ,
@@ -283,10 +306,6 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
283
306
if p. kind ( ) == SyntaxKind :: COMMA && is_closing_token ( code. kind ( ) ) {
284
307
pattern. next ( ) ;
285
308
}
286
- } else if code. kind ( ) == SyntaxKind :: SEMICOLON {
287
- // If the pattern ends but the code still has a trailing semicolon, accept the match.
288
- // Allows to match `let x = y; ...` with `let $a = $b`.
289
- return Ok ( ( ) ) ;
290
309
}
291
310
292
311
// Consume an element from the pattern and make sure it matches.
@@ -312,6 +331,9 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
312
331
) ;
313
332
}
314
333
None => {
334
+ if code. kind ( ) == SyntaxKind :: SEMICOLON {
335
+ return Err ( MatchFailed { reason : None , missing_semicolon : true } ) ;
336
+ }
315
337
fail_match ! ( "Pattern exhausted, while code remains: `{}`" , code. text( ) ) ;
316
338
}
317
339
}
0 commit comments