@@ -122,6 +122,16 @@ enum Phase<'a> {
122
122
Second ( & ' a mut Match ) ,
123
123
}
124
124
125
+ #[ derive( Debug ) ]
126
+ enum MatchRange {
127
+ Full ,
128
+ // FIXME: Should be an Err(), so that it can be threaded up?
129
+ // Otherwise all code returning a MatchRange must check that on success and take it into account, even if it's only a "high level" thing for now
130
+ // After all, a partial match can only be triggered if the pattern does not match _anymore_, but did up to a certain point (ie. pattern
131
+ // exhausted but the current SyntaxNode still has a trailing semicolon)
132
+ Partial ( FileRange ) ,
133
+ }
134
+
125
135
impl < ' db , ' sema > Matcher < ' db , ' sema > {
126
136
fn try_match (
127
137
rule : & ResolvedRule ,
@@ -131,10 +141,17 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
131
141
) -> Result < Match , MatchFailed > {
132
142
let match_state = Matcher { sema, restrict_range : restrict_range. clone ( ) , rule } ;
133
143
// First pass at matching, where we check that node types and idents match.
134
- match_state. attempt_match_node ( & mut Phase :: First , & rule. pattern . node , code) ?;
135
- match_state. validate_range ( & sema. original_range ( code) ) ?;
144
+ let matched_range =
145
+ match_state. attempt_match_node ( & mut Phase :: First , & rule. pattern . node , code) ?;
146
+
147
+ let range = match matched_range {
148
+ MatchRange :: Full => sema. original_range ( code) ,
149
+ MatchRange :: Partial ( r) => r,
150
+ } ;
151
+
152
+ match_state. validate_range ( & range) ?;
136
153
let mut the_match = Match {
137
- range : sema . original_range ( code ) ,
154
+ range,
138
155
matched_node : code. clone ( ) ,
139
156
placeholder_values : FxHashMap :: default ( ) ,
140
157
ignored_comments : Vec :: new ( ) ,
@@ -175,14 +192,16 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
175
192
phase : & mut Phase ,
176
193
pattern : & SyntaxNode ,
177
194
code : & SyntaxNode ,
178
- ) -> Result < ( ) , MatchFailed > {
195
+ ) -> Result < MatchRange , MatchFailed > {
179
196
// Handle placeholders.
180
197
if let Some ( placeholder) = self . get_placeholder_for_node ( pattern) {
181
198
for constraint in & placeholder. constraints {
182
199
self . check_constraint ( constraint, code) ?;
183
200
}
184
201
if let Phase :: Second ( matches_out) = phase {
185
- let original_range = self . sema . original_range ( code) ;
202
+ let mut original_range = self . sema . original_range ( code) ;
203
+ original_range. range =
204
+ original_range. range . intersect ( matches_out. range . range ) . unwrap ( ) ;
186
205
// We validated the range for the node when we started the match, so the placeholder
187
206
// probably can't fail range validation, but just to be safe...
188
207
self . validate_range ( & original_range) ?;
@@ -191,7 +210,8 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
191
210
PlaceholderMatch :: new ( Some ( code) , original_range) ,
192
211
) ;
193
212
}
194
- return Ok ( ( ) ) ;
213
+ // Range not relevant here
214
+ return Ok ( MatchRange :: Full ) ;
195
215
}
196
216
// We allow a UFCS call to match a method call, provided they resolve to the same function.
197
217
if let Some ( pattern_ufcs) = self . rule . pattern . ufcs_function_calls . get ( pattern) {
@@ -229,14 +249,21 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
229
249
phase : & mut Phase ,
230
250
pattern : & SyntaxNode ,
231
251
code : & SyntaxNode ,
232
- ) -> Result < ( ) , MatchFailed > {
252
+ ) -> Result < MatchRange , MatchFailed > {
233
253
let pattern_it = PatternIterator :: new ( pattern) ;
234
254
let code_it = code. children_with_tokens ( ) ;
235
255
256
+ // WIP: Only allow missing semicolons on `let = ...(;)`
236
257
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 ( ( ) )
258
+ Err ( MatchFailed { missing_semicolon : true , .. } ) => {
259
+ let mut original_range = self . sema . original_range ( code) ;
260
+ let text_range = original_range. range ;
261
+ original_range. range = syntax:: TextRange :: new (
262
+ text_range. start ( ) ,
263
+ text_range. end ( ) - syntax:: TextSize :: from ( 1 ) ,
264
+ ) ;
265
+
266
+ Ok ( MatchRange :: Partial ( original_range) )
240
267
}
241
268
res => res,
242
269
}
@@ -247,7 +274,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
247
274
phase : & mut Phase ,
248
275
pattern : & SyntaxNode ,
249
276
code : & SyntaxNode ,
250
- ) -> Result < ( ) , MatchFailed > {
277
+ ) -> Result < MatchRange , MatchFailed > {
251
278
self . attempt_match_sequences (
252
279
phase,
253
280
PatternIterator :: new ( pattern) ,
@@ -260,15 +287,15 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
260
287
phase : & mut Phase ,
261
288
pattern_it : PatternIterator ,
262
289
mut code_it : SyntaxElementChildren ,
263
- ) -> Result < ( ) , MatchFailed > {
290
+ ) -> Result < MatchRange , MatchFailed > {
264
291
let mut pattern_it = pattern_it. peekable ( ) ;
265
292
loop {
266
293
match phase. next_non_trivial ( & mut code_it) {
267
294
None => {
268
295
if let Some ( p) = pattern_it. next ( ) {
269
296
fail_match ! ( "Part of the pattern was unmatched: {:?}" , p) ;
270
297
}
271
- return Ok ( ( ) ) ;
298
+ return Ok ( MatchRange :: Full ) ;
272
299
}
273
300
Some ( SyntaxElement :: Token ( c) ) => {
274
301
self . attempt_match_token ( phase, & mut pattern_it, & c) ?;
@@ -332,6 +359,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
332
359
}
333
360
None => {
334
361
if code. kind ( ) == SyntaxKind :: SEMICOLON {
362
+ // FIXME: MatchRange::Partial?
335
363
return Err ( MatchFailed { reason : None , missing_semicolon : true } ) ;
336
364
}
337
365
fail_match ! ( "Pattern exhausted, while code remains: `{}`" , code. text( ) ) ;
@@ -365,7 +393,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
365
393
phase : & mut Phase ,
366
394
pattern : & SyntaxNode ,
367
395
code : & SyntaxNode ,
368
- ) -> Result < ( ) , MatchFailed > {
396
+ ) -> Result < MatchRange , MatchFailed > {
369
397
if let Some ( pattern_resolved) = self . rule . pattern . resolved_paths . get ( pattern) {
370
398
let pattern_path = ast:: Path :: cast ( pattern. clone ( ) ) . unwrap ( ) ;
371
399
let code_path = ast:: Path :: cast ( code. clone ( ) ) . unwrap ( ) ;
@@ -397,18 +425,18 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
397
425
} else {
398
426
return self . attempt_match_node_children ( phase, pattern, code) ;
399
427
}
400
- Ok ( ( ) )
428
+ Ok ( MatchRange :: Full )
401
429
}
402
430
403
431
fn attempt_match_opt < T : AstNode > (
404
432
& self ,
405
433
phase : & mut Phase ,
406
434
pattern : Option < T > ,
407
435
code : Option < T > ,
408
- ) -> Result < ( ) , MatchFailed > {
436
+ ) -> Result < MatchRange , MatchFailed > {
409
437
match ( pattern, code) {
410
438
( Some ( p) , Some ( c) ) => self . attempt_match_node ( phase, & p. syntax ( ) , & c. syntax ( ) ) ,
411
- ( None , None ) => Ok ( ( ) ) ,
439
+ ( None , None ) => Ok ( MatchRange :: Full ) ,
412
440
( Some ( p) , None ) => fail_match ! ( "Pattern `{}` had nothing to match" , p. syntax( ) . text( ) ) ,
413
441
( None , Some ( c) ) => {
414
442
fail_match ! ( "Nothing in pattern to match code `{}`" , c. syntax( ) . text( ) )
@@ -423,7 +451,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
423
451
phase : & mut Phase ,
424
452
pattern : & SyntaxNode ,
425
453
code : & SyntaxNode ,
426
- ) -> Result < ( ) , MatchFailed > {
454
+ ) -> Result < MatchRange , MatchFailed > {
427
455
// Build a map keyed by field name.
428
456
let mut fields_by_name = FxHashMap :: default ( ) ;
429
457
for child in code. children ( ) {
@@ -461,7 +489,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
461
489
unmatched_fields
462
490
) ;
463
491
}
464
- Ok ( ( ) )
492
+ Ok ( MatchRange :: Full )
465
493
}
466
494
467
495
/// Outside of token trees, a placeholder can only match a single AST node, whereas in a token
@@ -473,7 +501,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
473
501
phase : & mut Phase ,
474
502
pattern : & SyntaxNode ,
475
503
code : & syntax:: SyntaxNode ,
476
- ) -> Result < ( ) , MatchFailed > {
504
+ ) -> Result < MatchRange , MatchFailed > {
477
505
let mut pattern = PatternIterator :: new ( pattern) . peekable ( ) ;
478
506
let mut children = code. children_with_tokens ( ) ;
479
507
while let Some ( child) = children. next ( ) {
@@ -548,15 +576,15 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
548
576
if let Some ( p) = pattern. next ( ) {
549
577
fail_match ! ( "Reached end of token tree in code, but pattern still has {:?}" , p) ;
550
578
}
551
- Ok ( ( ) )
579
+ Ok ( MatchRange :: Full )
552
580
}
553
581
554
582
fn attempt_match_ufcs_to_method_call (
555
583
& self ,
556
584
phase : & mut Phase ,
557
585
pattern_ufcs : & UfcsCallInfo ,
558
586
code : & ast:: MethodCallExpr ,
559
- ) -> Result < ( ) , MatchFailed > {
587
+ ) -> Result < MatchRange , MatchFailed > {
560
588
use ast:: ArgListOwner ;
561
589
let code_resolved_function = self
562
590
. sema
@@ -605,8 +633,10 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
605
633
code. arg_list ( ) . ok_or_else ( || match_error ! ( "Code method call has no args" ) ) ?. args ( ) ;
606
634
loop {
607
635
match ( pattern_args. next ( ) , code_args. next ( ) ) {
608
- ( None , None ) => return Ok ( ( ) ) ,
609
- ( p, c) => self . attempt_match_opt ( phase, p, c) ?,
636
+ ( None , None ) => return Ok ( MatchRange :: Full ) ,
637
+ ( p, c) => {
638
+ let _ = self . attempt_match_opt ( phase, p, c) ?;
639
+ }
610
640
}
611
641
}
612
642
}
@@ -616,7 +646,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
616
646
phase : & mut Phase ,
617
647
pattern_ufcs : & UfcsCallInfo ,
618
648
code : & ast:: CallExpr ,
619
- ) -> Result < ( ) , MatchFailed > {
649
+ ) -> Result < MatchRange , MatchFailed > {
620
650
use ast:: ArgListOwner ;
621
651
// Check that the first argument is the expected type.
622
652
if let ( Some ( pattern_type) , Some ( expr) ) = (
0 commit comments