@@ -169,6 +169,39 @@ Scope::lookup (const CanonicalPath &ident, NodeId *id)
169
169
return lookup != UNKNOWN_NODEID;
170
170
}
171
171
172
+ bool
173
+ Scope::lookup_decl_type (NodeId id, Rib::ItemType *type)
174
+ {
175
+ bool found = false ;
176
+ iterate ([&] (const Rib *r) -> bool {
177
+ if (r->decl_was_declared_here (id))
178
+ {
179
+ bool ok = r->lookup_decl_type (id, type);
180
+ rust_assert (ok);
181
+ found = true ;
182
+ return false ;
183
+ }
184
+ return true ;
185
+ });
186
+ return found;
187
+ }
188
+
189
+ bool
190
+ Scope::lookup_rib_for_decl (NodeId id, const Rib **rib)
191
+ {
192
+ bool found = false ;
193
+ iterate ([&] (const Rib *r) -> bool {
194
+ if (r->decl_was_declared_here (id))
195
+ {
196
+ *rib = r;
197
+ found = true ;
198
+ return false ;
199
+ }
200
+ return true ;
201
+ });
202
+ return found;
203
+ }
204
+
172
205
void
173
206
Scope::iterate (std::function<bool (Rib *)> cb)
174
207
{
@@ -435,6 +468,7 @@ Resolver::insert_resolved_name (NodeId refId, NodeId defId)
435
468
{
436
469
resolved_names[refId] = defId;
437
470
get_name_scope ().append_reference_for_def (refId, defId);
471
+ insert_captured_item (defId);
438
472
}
439
473
440
474
bool
@@ -531,5 +565,104 @@ Resolver::lookup_resolved_misc (NodeId refId, NodeId *defId)
531
565
return true ;
532
566
}
533
567
568
+ void
569
+ Resolver::push_closure_context (NodeId closure_expr_id)
570
+ {
571
+ auto it = closures_capture_mappings.find (closure_expr_id);
572
+ rust_assert (it == closures_capture_mappings.end ());
573
+
574
+ closures_capture_mappings.insert ({closure_expr_id, {}});
575
+ closure_context.push_back (closure_expr_id);
576
+ }
577
+
578
+ void
579
+ Resolver::pop_closure_context ()
580
+ {
581
+ rust_assert (!closure_context.empty ());
582
+ closure_context.pop_back ();
583
+ }
584
+
585
+ void
586
+ Resolver::insert_captured_item (NodeId id)
587
+ {
588
+ // nothing to do unless we are in a closure context
589
+ if (closure_context.empty ())
590
+ return ;
591
+
592
+ // check that this is a VAR_DECL?
593
+ Scope &name_scope = get_name_scope ();
594
+ Rib::ItemType type = Rib::ItemType::Unknown;
595
+ bool found = name_scope.lookup_decl_type (id, &type);
596
+ if (!found)
597
+ return ;
598
+
599
+ // RIB Function { let a, let b } id = 1;
600
+ // RIB Closure { let c } id = 2;
601
+ // RIB IfStmt { <bind a>} id = 3;
602
+ // RIB ... { ... } id = 4
603
+ //
604
+ // if we have a resolved_node_id of 'a' and the current rib is '3' we know
605
+ // this is binding exists in a rib with id < the closure rib id, other wise
606
+ // its just a normal binding and we don't care
607
+ //
608
+ // Problem the node id's dont work like this because the inner most items are
609
+ // created first so this means the root will have a larger id and a simple
610
+ // less than or greater than check wont work for more complex scoping cases
611
+ // but we can use our current rib context to figure this out by checking if
612
+ // the rib id the decl we care about exists prior to the rib for the closure
613
+ // id
614
+
615
+ const Rib *r = nullptr ;
616
+ bool ok = name_scope.lookup_rib_for_decl (id, &r);
617
+ rust_assert (ok);
618
+ NodeId decl_rib_node_id = r->get_node_id ();
619
+
620
+ // iterate the closure context and add in the mapping for all to handle the
621
+ // case of nested closures
622
+ for (auto &closure_expr_id : closure_context)
623
+ {
624
+ if (!decl_needs_capture (decl_rib_node_id, closure_expr_id, name_scope))
625
+ continue ;
626
+
627
+ // is this a valid binding to take
628
+ bool is_var_decl_p = type == Rib::ItemType::Var;
629
+ if (!is_var_decl_p)
630
+ {
631
+ // FIXME is this an error case?
632
+ return ;
633
+ }
634
+
635
+ // append it to the context info
636
+ auto it = closures_capture_mappings.find (closure_expr_id);
637
+ rust_assert (it != closures_capture_mappings.end ());
638
+
639
+ it->second .insert (id);
640
+ }
641
+ }
642
+
643
+ bool
644
+ Resolver::decl_needs_capture (NodeId decl_rib_node_id,
645
+ NodeId closure_rib_node_id, const Scope &scope)
646
+ {
647
+ for (const auto &rib : scope.get_context ())
648
+ {
649
+ bool rib_is_closure = rib->get_node_id () == closure_rib_node_id;
650
+ bool rib_is_decl = rib->get_node_id () == decl_rib_node_id;
651
+ if (rib_is_closure)
652
+ return false ;
653
+ else if (rib_is_decl)
654
+ return true ;
655
+ }
656
+ return false ;
657
+ }
658
+
659
+ const std::set<NodeId> &
660
+ Resolver::get_captures (NodeId id) const
661
+ {
662
+ auto it = closures_capture_mappings.find (id);
663
+ rust_assert (it != closures_capture_mappings.end ());
664
+ return it->second ;
665
+ }
666
+
534
667
} // namespace Resolver
535
668
} // namespace Rust
0 commit comments