@@ -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
+ // TODO: 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
+ // TODO: 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 ( ) {
@@ -546,15 +574,15 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
546
574
if let Some ( p) = pattern. next ( ) {
547
575
fail_match ! ( "Reached end of token tree in code, but pattern still has {:?}" , p) ;
548
576
}
549
- Ok ( ( ) )
577
+ Ok ( MatchRange :: Full )
550
578
}
551
579
552
580
fn attempt_match_ufcs_to_method_call (
553
581
& self ,
554
582
phase : & mut Phase ,
555
583
pattern_ufcs : & UfcsCallInfo ,
556
584
code : & ast:: MethodCallExpr ,
557
- ) -> Result < ( ) , MatchFailed > {
585
+ ) -> Result < MatchRange , MatchFailed > {
558
586
use ast:: ArgListOwner ;
559
587
let code_resolved_function = self
560
588
. sema
@@ -603,8 +631,10 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
603
631
code. arg_list ( ) . ok_or_else ( || match_error ! ( "Code method call has no args" ) ) ?. args ( ) ;
604
632
loop {
605
633
match ( pattern_args. next ( ) , code_args. next ( ) ) {
606
- ( None , None ) => return Ok ( ( ) ) ,
607
- ( p, c) => self . attempt_match_opt ( phase, p, c) ?,
634
+ ( None , None ) => return Ok ( MatchRange :: Full ) ,
635
+ ( p, c) => {
636
+ let _ = self . attempt_match_opt ( phase, p, c) ?;
637
+ }
608
638
}
609
639
}
610
640
}
@@ -614,7 +644,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
614
644
phase : & mut Phase ,
615
645
pattern_ufcs : & UfcsCallInfo ,
616
646
code : & ast:: CallExpr ,
617
- ) -> Result < ( ) , MatchFailed > {
647
+ ) -> Result < MatchRange , MatchFailed > {
618
648
use ast:: ArgListOwner ;
619
649
// Check that the first argument is the expected type.
620
650
if let ( Some ( pattern_type) , Some ( expr) ) = (
0 commit comments