@@ -10,6 +10,7 @@ use std::ops::{Deref, Index};
10
10
11
11
use base_db:: CrateId ;
12
12
use cfg:: { CfgExpr , CfgOptions } ;
13
+ use either:: Either ;
13
14
use hir_expand:: { name:: Name , ExpandError , InFile } ;
14
15
use la_arena:: { Arena , ArenaMap , Idx , RawIdx } ;
15
16
use rustc_hash:: FxHashMap ;
@@ -22,7 +23,8 @@ use crate::{
22
23
db:: DefDatabase ,
23
24
expander:: Expander ,
24
25
hir:: {
25
- dummy_expr_id, Binding , BindingId , Expr , ExprId , Label , LabelId , Pat , PatId , RecordFieldPat ,
26
+ dummy_expr_id, Array , AsmOperand , Binding , BindingId , Expr , ExprId , ExprOrPatId , Label ,
27
+ LabelId , Pat , PatId , RecordFieldPat , Statement ,
26
28
} ,
27
29
item_tree:: AttrOwner ,
28
30
nameres:: DefMap ,
@@ -67,9 +69,12 @@ pub type LabelSource = InFile<LabelPtr>;
67
69
pub type FieldPtr = AstPtr < ast:: RecordExprField > ;
68
70
pub type FieldSource = InFile < FieldPtr > ;
69
71
70
- pub type PatFieldPtr = AstPtr < ast:: RecordPatField > ;
72
+ pub type PatFieldPtr = AstPtr < Either < ast:: RecordExprField , ast :: RecordPatField > > ;
71
73
pub type PatFieldSource = InFile < PatFieldPtr > ;
72
74
75
+ pub type ExprOrPatPtr = AstPtr < Either < ast:: Expr , ast:: Pat > > ;
76
+ pub type ExprOrPatSource = InFile < ExprOrPatPtr > ;
77
+
73
78
/// An item body together with the mapping from syntax nodes to HIR expression
74
79
/// IDs. This is needed to go from e.g. a position in a file to the HIR
75
80
/// expression containing it; but for type inference etc., we want to operate on
@@ -83,11 +88,13 @@ pub type PatFieldSource = InFile<PatFieldPtr>;
83
88
/// this properly for macros.
84
89
#[ derive( Default , Debug , Eq , PartialEq ) ]
85
90
pub struct BodySourceMap {
86
- expr_map : FxHashMap < ExprSource , ExprId > ,
91
+ // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
92
+ // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
93
+ expr_map : FxHashMap < ExprSource , ExprOrPatId > ,
87
94
expr_map_back : ArenaMap < ExprId , ExprSource > ,
88
95
89
96
pat_map : FxHashMap < PatSource , PatId > ,
90
- pat_map_back : ArenaMap < PatId , PatSource > ,
97
+ pat_map_back : ArenaMap < PatId , ExprOrPatSource > ,
91
98
92
99
label_map : FxHashMap < LabelSource , LabelId > ,
93
100
label_map_back : ArenaMap < LabelId , LabelSource > ,
@@ -286,7 +293,8 @@ impl Body {
286
293
| Pat :: Path ( ..)
287
294
| Pat :: ConstBlock ( ..)
288
295
| Pat :: Wild
289
- | Pat :: Missing => { }
296
+ | Pat :: Missing
297
+ | Pat :: Expr ( _) => { }
290
298
& Pat :: Bind { subpat, .. } => {
291
299
if let Some ( subpat) = subpat {
292
300
f ( subpat) ;
@@ -322,6 +330,143 @@ impl Body {
322
330
None => true ,
323
331
}
324
332
}
333
+
334
+ pub fn walk_child_exprs ( & self , expr_id : ExprId , mut f : impl FnMut ( ExprId ) ) {
335
+ let expr = & self [ expr_id] ;
336
+ match expr {
337
+ Expr :: Continue { .. }
338
+ | Expr :: Const ( _)
339
+ | Expr :: Missing
340
+ | Expr :: Path ( _)
341
+ | Expr :: OffsetOf ( _)
342
+ | Expr :: Literal ( _)
343
+ | Expr :: Underscore => { }
344
+ Expr :: InlineAsm ( it) => it. operands . iter ( ) . for_each ( |( _, op) | match op {
345
+ AsmOperand :: In { expr, .. }
346
+ | AsmOperand :: Out { expr : Some ( expr) , .. }
347
+ | AsmOperand :: InOut { expr, .. } => f ( * expr) ,
348
+ AsmOperand :: SplitInOut { in_expr, out_expr, .. } => {
349
+ f ( * in_expr) ;
350
+ if let Some ( out_expr) = out_expr {
351
+ f ( * out_expr) ;
352
+ }
353
+ }
354
+ AsmOperand :: Out { expr : None , .. }
355
+ | AsmOperand :: Const ( _)
356
+ | AsmOperand :: Label ( _)
357
+ | AsmOperand :: Sym ( _) => ( ) ,
358
+ } ) ,
359
+ Expr :: If { condition, then_branch, else_branch } => {
360
+ f ( * condition) ;
361
+ f ( * then_branch) ;
362
+ if let & Some ( else_branch) = else_branch {
363
+ f ( else_branch) ;
364
+ }
365
+ }
366
+ Expr :: Let { expr, .. } => {
367
+ f ( * expr) ;
368
+ }
369
+ Expr :: Block { statements, tail, .. }
370
+ | Expr :: Unsafe { statements, tail, .. }
371
+ | Expr :: Async { statements, tail, .. } => {
372
+ for stmt in statements. iter ( ) {
373
+ match stmt {
374
+ Statement :: Let { initializer, else_branch, pat, .. } => {
375
+ if let & Some ( expr) = initializer {
376
+ f ( expr) ;
377
+ }
378
+ if let & Some ( expr) = else_branch {
379
+ f ( expr) ;
380
+ }
381
+ self . walk_exprs_in_pat ( * pat, & mut f) ;
382
+ }
383
+ Statement :: Expr { expr : expression, .. } => f ( * expression) ,
384
+ Statement :: Item => ( ) ,
385
+ }
386
+ }
387
+ if let & Some ( expr) = tail {
388
+ f ( expr) ;
389
+ }
390
+ }
391
+ Expr :: Loop { body, .. } => f ( * body) ,
392
+ Expr :: Call { callee, args, .. } => {
393
+ f ( * callee) ;
394
+ args. iter ( ) . copied ( ) . for_each ( f) ;
395
+ }
396
+ Expr :: MethodCall { receiver, args, .. } => {
397
+ f ( * receiver) ;
398
+ args. iter ( ) . copied ( ) . for_each ( f) ;
399
+ }
400
+ Expr :: Match { expr, arms } => {
401
+ f ( * expr) ;
402
+ arms. iter ( ) . map ( |arm| arm. expr ) . for_each ( f) ;
403
+ }
404
+ Expr :: Break { expr, .. }
405
+ | Expr :: Return { expr }
406
+ | Expr :: Yield { expr }
407
+ | Expr :: Yeet { expr } => {
408
+ if let & Some ( expr) = expr {
409
+ f ( expr) ;
410
+ }
411
+ }
412
+ Expr :: Become { expr } => f ( * expr) ,
413
+ Expr :: RecordLit { fields, spread, .. } => {
414
+ for field in fields. iter ( ) {
415
+ f ( field. expr ) ;
416
+ }
417
+ if let & Some ( expr) = spread {
418
+ f ( expr) ;
419
+ }
420
+ }
421
+ Expr :: Closure { body, .. } => {
422
+ f ( * body) ;
423
+ }
424
+ Expr :: BinaryOp { lhs, rhs, .. } => {
425
+ f ( * lhs) ;
426
+ f ( * rhs) ;
427
+ }
428
+ Expr :: Range { lhs, rhs, .. } => {
429
+ if let & Some ( lhs) = rhs {
430
+ f ( lhs) ;
431
+ }
432
+ if let & Some ( rhs) = lhs {
433
+ f ( rhs) ;
434
+ }
435
+ }
436
+ Expr :: Index { base, index, .. } => {
437
+ f ( * base) ;
438
+ f ( * index) ;
439
+ }
440
+ Expr :: Field { expr, .. }
441
+ | Expr :: Await { expr }
442
+ | Expr :: Cast { expr, .. }
443
+ | Expr :: Ref { expr, .. }
444
+ | Expr :: UnaryOp { expr, .. }
445
+ | Expr :: Box { expr } => {
446
+ f ( * expr) ;
447
+ }
448
+ Expr :: Tuple { exprs, .. } => exprs. iter ( ) . copied ( ) . for_each ( f) ,
449
+ Expr :: Array ( a) => match a {
450
+ Array :: ElementList { elements, .. } => elements. iter ( ) . copied ( ) . for_each ( f) ,
451
+ Array :: Repeat { initializer, repeat } => {
452
+ f ( * initializer) ;
453
+ f ( * repeat)
454
+ }
455
+ } ,
456
+ & Expr :: Assignment { target, value } => {
457
+ self . walk_exprs_in_pat ( target, & mut f) ;
458
+ f ( value) ;
459
+ }
460
+ }
461
+ }
462
+
463
+ pub fn walk_exprs_in_pat ( & self , pat_id : PatId , f : & mut impl FnMut ( ExprId ) ) {
464
+ self . walk_pats ( pat_id, & mut |pat| {
465
+ if let Pat :: Expr ( expr) | Pat :: ConstBlock ( expr) = self [ pat] {
466
+ f ( expr) ;
467
+ }
468
+ } ) ;
469
+ }
325
470
}
326
471
327
472
impl Default for Body {
@@ -375,11 +520,18 @@ impl Index<BindingId> for Body {
375
520
// FIXME: Change `node_` prefix to something more reasonable.
376
521
// Perhaps `expr_syntax` and `expr_id`?
377
522
impl BodySourceMap {
523
+ pub fn expr_or_pat_syntax ( & self , id : ExprOrPatId ) -> Result < ExprOrPatSource , SyntheticSyntax > {
524
+ match id {
525
+ ExprOrPatId :: ExprId ( id) => self . expr_syntax ( id) . map ( |it| it. map ( AstPtr :: wrap_left) ) ,
526
+ ExprOrPatId :: PatId ( id) => self . pat_syntax ( id) ,
527
+ }
528
+ }
529
+
378
530
pub fn expr_syntax ( & self , expr : ExprId ) -> Result < ExprSource , SyntheticSyntax > {
379
531
self . expr_map_back . get ( expr) . cloned ( ) . ok_or ( SyntheticSyntax )
380
532
}
381
533
382
- pub fn node_expr ( & self , node : InFile < & ast:: Expr > ) -> Option < ExprId > {
534
+ pub fn node_expr ( & self , node : InFile < & ast:: Expr > ) -> Option < ExprOrPatId > {
383
535
let src = node. map ( AstPtr :: new) ;
384
536
self . expr_map . get ( & src) . cloned ( )
385
537
}
@@ -395,7 +547,7 @@ impl BodySourceMap {
395
547
self . expansions . iter ( ) . map ( |( & a, & b) | ( a, b) )
396
548
}
397
549
398
- pub fn pat_syntax ( & self , pat : PatId ) -> Result < PatSource , SyntheticSyntax > {
550
+ pub fn pat_syntax ( & self , pat : PatId ) -> Result < ExprOrPatSource , SyntheticSyntax > {
399
551
self . pat_map_back . get ( pat) . cloned ( ) . ok_or ( SyntheticSyntax )
400
552
}
401
553
@@ -428,7 +580,7 @@ impl BodySourceMap {
428
580
self . pat_field_map_back [ & pat]
429
581
}
430
582
431
- pub fn macro_expansion_expr ( & self , node : InFile < & ast:: MacroExpr > ) -> Option < ExprId > {
583
+ pub fn macro_expansion_expr ( & self , node : InFile < & ast:: MacroExpr > ) -> Option < ExprOrPatId > {
432
584
let src = node. map ( AstPtr :: new) . map ( AstPtr :: upcast :: < ast:: MacroExpr > ) . map ( AstPtr :: upcast) ;
433
585
self . expr_map . get ( & src) . copied ( )
434
586
}
@@ -444,16 +596,20 @@ impl BodySourceMap {
444
596
node : InFile < & ast:: FormatArgsExpr > ,
445
597
) -> Option < & [ ( syntax:: TextRange , Name ) ] > {
446
598
let src = node. map ( AstPtr :: new) . map ( AstPtr :: upcast :: < ast:: Expr > ) ;
447
- self . template_map . as_ref ( ) ?. 0 . get ( self . expr_map . get ( & src) ?) . map ( std:: ops:: Deref :: deref)
599
+ self . template_map
600
+ . as_ref ( ) ?
601
+ . 0
602
+ . get ( & self . expr_map . get ( & src) ?. as_expr ( ) ?)
603
+ . map ( std:: ops:: Deref :: deref)
448
604
}
449
605
450
606
pub fn asm_template_args (
451
607
& self ,
452
608
node : InFile < & ast:: AsmExpr > ,
453
609
) -> Option < ( ExprId , & [ Vec < ( syntax:: TextRange , usize ) > ] ) > {
454
610
let src = node. map ( AstPtr :: new) . map ( AstPtr :: upcast :: < ast:: Expr > ) ;
455
- let expr = self . expr_map . get ( & src) ?;
456
- Some ( * expr) . zip ( self . template_map . as_ref ( ) ?. 1 . get ( expr) . map ( std:: ops:: Deref :: deref) )
611
+ let expr = self . expr_map . get ( & src) ?. as_expr ( ) ? ;
612
+ Some ( expr) . zip ( self . template_map . as_ref ( ) ?. 1 . get ( & expr) . map ( std:: ops:: Deref :: deref) )
457
613
}
458
614
459
615
/// Get a reference to the body source map's diagnostics.
0 commit comments