@@ -10,6 +10,7 @@ use std::ops::{Deref, Index};
1010
1111use base_db:: CrateId ;
1212use cfg:: { CfgExpr , CfgOptions } ;
13+ use either:: Either ;
1314use hir_expand:: { name:: Name , ExpandError , InFile } ;
1415use la_arena:: { Arena , ArenaMap , Idx , RawIdx } ;
1516use rustc_hash:: FxHashMap ;
@@ -22,7 +23,8 @@ use crate::{
2223 db:: DefDatabase ,
2324 expander:: Expander ,
2425 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 ,
2628 } ,
2729 item_tree:: AttrOwner ,
2830 nameres:: DefMap ,
@@ -67,9 +69,12 @@ pub type LabelSource = InFile<LabelPtr>;
6769pub type FieldPtr = AstPtr < ast:: RecordExprField > ;
6870pub type FieldSource = InFile < FieldPtr > ;
6971
70- pub type PatFieldPtr = AstPtr < ast:: RecordPatField > ;
72+ pub type PatFieldPtr = AstPtr < Either < ast:: RecordExprField , ast :: RecordPatField > > ;
7173pub type PatFieldSource = InFile < PatFieldPtr > ;
7274
75+ pub type ExprOrPatPtr = AstPtr < Either < ast:: Expr , ast:: Pat > > ;
76+ pub type ExprOrPatSource = InFile < ExprOrPatPtr > ;
77+
7378/// An item body together with the mapping from syntax nodes to HIR expression
7479/// IDs. This is needed to go from e.g. a position in a file to the HIR
7580/// expression containing it; but for type inference etc., we want to operate on
@@ -83,11 +88,13 @@ pub type PatFieldSource = InFile<PatFieldPtr>;
8388/// this properly for macros.
8489#[ derive( Default , Debug , Eq , PartialEq ) ]
8590pub 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 > ,
8794 expr_map_back : ArenaMap < ExprId , ExprSource > ,
8895
8996 pat_map : FxHashMap < PatSource , PatId > ,
90- pat_map_back : ArenaMap < PatId , PatSource > ,
97+ pat_map_back : ArenaMap < PatId , ExprOrPatSource > ,
9198
9299 label_map : FxHashMap < LabelSource , LabelId > ,
93100 label_map_back : ArenaMap < LabelId , LabelSource > ,
@@ -286,7 +293,8 @@ impl Body {
286293 | Pat :: Path ( ..)
287294 | Pat :: ConstBlock ( ..)
288295 | Pat :: Wild
289- | Pat :: Missing => { }
296+ | Pat :: Missing
297+ | Pat :: Expr ( _) => { }
290298 & Pat :: Bind { subpat, .. } => {
291299 if let Some ( subpat) = subpat {
292300 f ( subpat) ;
@@ -322,6 +330,143 @@ impl Body {
322330 None => true ,
323331 }
324332 }
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+ }
325470}
326471
327472impl Default for Body {
@@ -375,11 +520,18 @@ impl Index<BindingId> for Body {
375520// FIXME: Change `node_` prefix to something more reasonable.
376521// Perhaps `expr_syntax` and `expr_id`?
377522impl 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+
378530 pub fn expr_syntax ( & self , expr : ExprId ) -> Result < ExprSource , SyntheticSyntax > {
379531 self . expr_map_back . get ( expr) . cloned ( ) . ok_or ( SyntheticSyntax )
380532 }
381533
382- pub fn node_expr ( & self , node : InFile < & ast:: Expr > ) -> Option < ExprId > {
534+ pub fn node_expr ( & self , node : InFile < & ast:: Expr > ) -> Option < ExprOrPatId > {
383535 let src = node. map ( AstPtr :: new) ;
384536 self . expr_map . get ( & src) . cloned ( )
385537 }
@@ -395,7 +547,7 @@ impl BodySourceMap {
395547 self . expansions . iter ( ) . map ( |( & a, & b) | ( a, b) )
396548 }
397549
398- pub fn pat_syntax ( & self , pat : PatId ) -> Result < PatSource , SyntheticSyntax > {
550+ pub fn pat_syntax ( & self , pat : PatId ) -> Result < ExprOrPatSource , SyntheticSyntax > {
399551 self . pat_map_back . get ( pat) . cloned ( ) . ok_or ( SyntheticSyntax )
400552 }
401553
@@ -428,7 +580,7 @@ impl BodySourceMap {
428580 self . pat_field_map_back [ & pat]
429581 }
430582
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 > {
432584 let src = node. map ( AstPtr :: new) . map ( AstPtr :: upcast :: < ast:: MacroExpr > ) . map ( AstPtr :: upcast) ;
433585 self . expr_map . get ( & src) . copied ( )
434586 }
@@ -444,16 +596,20 @@ impl BodySourceMap {
444596 node : InFile < & ast:: FormatArgsExpr > ,
445597 ) -> Option < & [ ( syntax:: TextRange , Name ) ] > {
446598 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)
448604 }
449605
450606 pub fn asm_template_args (
451607 & self ,
452608 node : InFile < & ast:: AsmExpr > ,
453609 ) -> Option < ( ExprId , & [ Vec < ( syntax:: TextRange , usize ) > ] ) > {
454610 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) )
457613 }
458614
459615 /// Get a reference to the body source map's diagnostics.
0 commit comments