1use std::collections::hash_map::Entry;
242use std::hash::{Hash as _, Hasher as _};
243use std::ops::Index;
244use std::rc::Rc;
245use std::sync::LazyLock;
246
247use ruff_index::{FrozenIndexVec, Idx, IndexVec, newtype_index};
248use ruff_text_size::TextRange;
249use rustc_hash::{FxBuildHasher, FxHashMap, FxHasher};
250use smallvec::SmallVec;
251use thin_vec::ThinVec;
252
253use crate::ast_ids::ScopedUseId;
254use crate::definition::{Definition, DefinitionCategory, DefinitionState};
255use crate::frozen::FrozenMap;
256use crate::member::ScopedMemberId;
257use crate::narrowing_constraints::{
258 ConstraintKey, NarrowingConstraints, NarrowingConstraintsBuilder, ScopedNarrowingConstraint,
259};
260use crate::place::{PlaceExprRef, ScopedPlaceId};
261use crate::predicate::{PredicateOrLiteral, Predicates, PredicatesBuilder, ScopedPredicateId};
262use crate::reachability_constraints::{
263 ReachabilityConstraints, ReachabilityConstraintsBuilder, ScopedReachabilityConstraintId,
264};
265use crate::scope::{FileScopeId, ScopeKind, ScopeLaziness};
266use crate::symbol::ScopedSymbolId;
267use crate::use_def::place_state::{
268 Bindings, Declarations, EnclosingSnapshot, LiveBindingsIterator, LiveDeclaration,
269 LiveDeclarationsIterator, PlaceState,
270};
271use crate::{
272 BoundnessAnalysis, EnclosingSnapshotResult, LoopHeader, PossiblyNarrowedPlaces, SemanticIndex,
273};
274
275mod exception_checkpoint;
276mod place_state;
277
278pub(super) use exception_checkpoint::ExceptionCheckpointKey;
279use exception_checkpoint::{ExceptionCheckpointSnapshot, ExceptionCheckpointState};
280pub use place_state::LiveBinding;
281pub use place_state::ScopedDefinitionId;
282pub(super) use place_state::{FutureDefinitions, PreviousDefinitions};
283
284#[derive(Copy, Clone, Debug, Eq, PartialEq)]
286pub(super) enum LiveBindingStatus {
287 Unbound,
289 PossiblyBound,
291 Bound,
293}
294
295#[newtype_index]
297#[derive(get_size2::GetSize)]
298pub struct LoopHeaderId;
299
300#[newtype_index]
302#[derive(get_size2::GetSize, salsa::SalsaValue)]
303struct InternedBindingsId;
304
305#[newtype_index]
307#[derive(get_size2::GetSize, salsa::SalsaValue)]
308struct InternedDeclarationsId;
309
310#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
311struct InternedPlaceStateId(InternedBindingsId, InternedDeclarationsId);
312
313impl InternedPlaceStateId {
314 fn bindings_id(self) -> InternedBindingsId {
315 self.0
316 }
317
318 fn declarations_id(self) -> InternedDeclarationsId {
319 self.1
320 }
321}
322
323struct PlaceStateInterner {
324 interned_bindings: RetainedBindingsBuilder,
325 interned_ids_by_bindings: hashbrown::HashTable<InternedBindingsId>,
326 interned_declarations: RetainedDeclarationsBuilder,
327 interned_ids_by_declarations: FxHashMap<Declarations, InternedDeclarationsId>,
328 undeclared_declarations_by_constraint:
330 IndexVec<ScopedReachabilityConstraintId, Option<InternedDeclarationsId>>,
331 always_unbound_bindings: Option<InternedBindingsId>,
333 always_undeclared_declarations: Option<InternedDeclarationsId>,
334}
335
336impl PlaceStateInterner {
337 fn with_capacity(bindings: usize, declaration_map: usize, declarations: usize) -> Self {
338 Self {
339 interned_bindings: RetainedBindingsBuilder::with_capacity(bindings),
340 interned_ids_by_bindings: hashbrown::HashTable::with_capacity(bindings),
341 interned_declarations: RetainedDeclarationsBuilder::with_capacity(declarations),
342 interned_ids_by_declarations: FxHashMap::with_capacity_and_hasher(
343 declaration_map,
344 FxBuildHasher,
345 ),
346 undeclared_declarations_by_constraint: IndexVec::new(),
347 always_unbound_bindings: None,
348 always_undeclared_declarations: None,
349 }
350 }
351
352 fn intern_bindings(&mut self, bindings: &Bindings) -> InternedBindingsId {
353 if bindings.is_always_unbound() {
354 if let Some(interned_id) = self.always_unbound_bindings {
355 return interned_id;
356 }
357
358 let interned_id = self.interned_bindings.push(bindings);
359 self.always_unbound_bindings = Some(interned_id);
360 return interned_id;
361 }
362
363 let hash = Self::hash_bindings(bindings.as_slice());
366 let interned_bindings = &mut self.interned_bindings;
367 let entry = self.interned_ids_by_bindings.entry(
368 hash,
369 |id| interned_bindings.get(*id) == bindings.as_slice(),
370 |id| Self::hash_bindings(interned_bindings.get(*id)),
371 );
372 match entry {
373 hashbrown::hash_table::Entry::Occupied(entry) => *entry.get(),
374 hashbrown::hash_table::Entry::Vacant(entry) => {
375 let interned_id = interned_bindings.push(bindings);
376 entry.insert(interned_id);
377 interned_id
378 }
379 }
380 }
381
382 fn hash_bindings(live_bindings: &[LiveBinding]) -> u64 {
383 let mut hasher = FxHasher::default();
384 live_bindings.hash(&mut hasher);
385 hasher.finish()
386 }
387
388 fn intern_declarations(&mut self, declarations: Declarations) -> InternedDeclarationsId {
389 if declarations.is_always_undeclared() {
390 if let Some(interned_id) = self.always_undeclared_declarations {
391 return interned_id;
392 }
393
394 let interned_id = self.interned_declarations.push(&declarations);
395 self.always_undeclared_declarations = Some(interned_id);
396 return interned_id;
397 }
398
399 if let Some(reachability_constraint) = declarations.undeclared_reachability_constraint()
400 && !reachability_constraint.is_terminal()
401 {
402 let index = reachability_constraint.index();
403 let len = self.undeclared_declarations_by_constraint.len();
404 if index >= len {
405 self.undeclared_declarations_by_constraint
406 .resize(index + 1, None);
407 } else if let Some(interned_id) =
408 self.undeclared_declarations_by_constraint[reachability_constraint]
409 {
410 return interned_id;
411 }
412
413 let interned_id = self.interned_declarations.push(&declarations);
414 self.undeclared_declarations_by_constraint[reachability_constraint] = Some(interned_id);
415 return interned_id;
416 }
417
418 match self.interned_ids_by_declarations.entry(declarations) {
419 Entry::Occupied(entry) => *entry.get(),
420 Entry::Vacant(entry) => {
421 let interned_id = self.interned_declarations.push(entry.key());
422 entry.insert(interned_id);
423 interned_id
424 }
425 }
426 }
427
428 fn intern_place_state(
429 &mut self,
430 bindings: &Bindings,
431 declarations: Declarations,
432 ) -> InternedPlaceStateId {
433 InternedPlaceStateId(
434 self.intern_bindings(bindings),
435 self.intern_declarations(declarations),
436 )
437 }
438
439 fn retain_place_state(
440 &mut self,
441 bindings: &Bindings,
442 declarations: Declarations,
443 ) -> InternedPlaceStateId {
444 let declarations_id = if declarations.undeclared_reachability_constraint().is_some() {
447 self.intern_declarations(declarations)
448 } else {
449 self.interned_declarations.push(&declarations)
450 };
451 InternedPlaceStateId(self.intern_bindings(bindings), declarations_id)
452 }
453}
454
455#[derive(Debug, PartialEq, Eq, get_size2::GetSize)]
461struct RetainedBindings {
462 ends: FrozenIndexVec<InternedBindingsId, u32>,
463 live_bindings: Box<[LiveBinding]>,
464}
465
466struct RetainedBindingsBuilder {
467 ends: IndexVec<InternedBindingsId, u32>,
468 live_bindings: Vec<LiveBinding>,
469}
470
471impl RetainedBindingsBuilder {
472 fn with_capacity(bindings: usize) -> Self {
473 Self {
474 ends: IndexVec::with_capacity(bindings),
475 live_bindings: Vec::with_capacity(bindings),
476 }
477 }
478
479 fn push(&mut self, bindings: &Bindings) -> InternedBindingsId {
480 self.live_bindings.extend_from_slice(bindings.as_slice());
483 let end = u32::try_from(self.live_bindings.len())
484 .expect("Expected live-bindings length to fit into a u32");
485 self.ends.push(end)
486 }
487
488 fn get(&self, index: InternedBindingsId) -> &[LiveBinding] {
489 let end = self.ends[index];
490 let start = if index.index() == 0 {
491 0
492 } else {
493 self.ends[InternedBindingsId::new(index.index() - 1)]
494 };
495 &self.live_bindings[start as usize..end as usize]
496 }
497
498 fn finish(
499 self,
500 narrowing_constraints: &mut NarrowingConstraintsBuilder,
501 reachability_constraints: &mut ReachabilityConstraintsBuilder,
502 ) -> RetainedBindings {
503 for binding in &self.live_bindings {
504 reachability_constraints.mark_used(binding.reachability_constraint());
505 narrowing_constraints.mark_used(binding.narrowing_constraint());
506 }
507 RetainedBindings {
508 ends: self.ends.into(),
509 live_bindings: self.live_bindings.into_boxed_slice(),
510 }
511 }
512}
513
514impl Index<InternedBindingsId> for RetainedBindings {
515 type Output = [LiveBinding];
516
517 fn index(&self, index: InternedBindingsId) -> &Self::Output {
518 let end = self.ends[index];
519 let start = if index.index() == 0 {
520 0
521 } else {
522 self.ends[InternedBindingsId::new(index.index() - 1)]
523 };
524 &self.live_bindings[start as usize..end as usize]
525 }
526}
527
528#[derive(Debug, PartialEq, Eq, get_size2::GetSize)]
530struct RetainedDeclarations {
531 ends: FrozenIndexVec<InternedDeclarationsId, u32>,
533 live_declarations: Box<[LiveDeclaration]>,
534}
535
536struct RetainedDeclarationsBuilder {
537 ends: IndexVec<InternedDeclarationsId, u32>,
538 live_declarations: Vec<LiveDeclaration>,
539}
540
541impl RetainedDeclarationsBuilder {
542 fn with_capacity(declarations: usize) -> Self {
543 Self {
544 ends: IndexVec::with_capacity(declarations),
545 live_declarations: Vec::with_capacity(declarations),
546 }
547 }
548
549 fn push(&mut self, declarations: &Declarations) -> InternedDeclarationsId {
550 self.live_declarations.extend(declarations.iter().cloned());
551 let end = u32::try_from(self.live_declarations.len())
552 .expect("Expected live-declarations length to fit into a u32");
553 self.ends.push(end)
554 }
555
556 fn finish(
557 self,
558 reachability_constraints: &mut ReachabilityConstraintsBuilder,
559 ) -> RetainedDeclarations {
560 for declaration in &self.live_declarations {
561 reachability_constraints.mark_used(declaration.reachability_constraint);
562 }
563 RetainedDeclarations {
564 ends: self.ends.into(),
565 live_declarations: self.live_declarations.into_boxed_slice(),
566 }
567 }
568}
569
570impl Index<InternedDeclarationsId> for RetainedDeclarations {
571 type Output = [LiveDeclaration];
572
573 fn index(&self, index: InternedDeclarationsId) -> &Self::Output {
574 let end = self.ends[index];
575 let start = if index.index() == 0 {
576 0
577 } else {
578 self.ends[InternedDeclarationsId::new(index.index() - 1)]
579 };
580 &self.live_declarations[start as usize..end as usize]
581 }
582}
583
584#[derive(Clone, Debug, Eq, PartialEq, get_size2::GetSize)]
585struct RetainedPlaceStates<T> {
586 end_of_scope: T,
587 reachable: T,
588}
589
590#[derive(Debug, PartialEq, Eq, get_size2::GetSize, salsa::SalsaValue)]
591struct DefinitionsAtDefinition<B, D> {
592 bindings: B,
593 declarations: Option<D>,
594}
595
596#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, get_size2::GetSize)]
597enum InternedEnclosingSnapshotId {
598 Constraint(ScopedNarrowingConstraint),
599 Bindings(InternedBindingsId),
600}
601
602#[derive(Debug, PartialEq, Eq, get_size2::GetSize, salsa::SalsaValue)]
604struct ConstraintTables<'db> {
605 predicates: Predicates<'db>,
606 predicate_narrowing_targets: PredicateNarrowingTargets,
607 reachability_constraints: ReachabilityConstraints,
608 narrowing_constraints: NarrowingConstraints,
609}
610
611#[derive(Debug, Default, PartialEq, Eq, get_size2::GetSize, salsa::SalsaValue)]
617pub struct PredicateNarrowingTargets(Box<[(ScopedPredicateId, ScopedPlaceId)]>);
618
619impl PredicateNarrowingTargets {
620 fn from_entries(mut entries: Vec<(ScopedPredicateId, ScopedPlaceId)>) -> Self {
621 entries.sort_unstable_by_key(|&(predicate, place)| (place, predicate));
622 entries.dedup();
623
624 Self(entries.into_boxed_slice())
625 }
626
627 pub fn contains(&self, predicate: ScopedPredicateId, place: ScopedPlaceId) -> bool {
629 self.0
630 .binary_search_by_key(&(place, predicate), |&(predicate, place)| {
631 (place, predicate)
632 })
633 .is_ok()
634 }
635
636 pub fn contains_place(&self, place: ScopedPlaceId) -> bool {
638 self.0
639 .binary_search_by_key(&place, |&(_, target)| target)
640 .is_ok()
641 }
642}
643
644#[derive(Debug, PartialEq, Eq, get_size2::GetSize)]
649struct UseDefMapExtra {
650 bindings_by_use: FrozenIndexVec<ScopedUseId, InternedBindingsId>,
652
653 multi_bindings_by_use: MultiBindingsByUse,
658
659 member_states: FrozenIndexVec<ScopedMemberId, RetainedPlaceStates<InternedPlaceStateId>>,
661
662 enclosing_snapshots: FrozenIndexVec<ScopedEnclosingSnapshotId, InternedEnclosingSnapshotId>,
664
665 loop_headers: FrozenIndexVec<LoopHeaderId, LoopHeader>,
667}
668
669static EMPTY_CONSTRAINT_TABLES: LazyLock<ConstraintTables<'static>> =
670 LazyLock::new(|| ConstraintTables {
671 predicates: IndexVec::new().into(),
672 predicate_narrowing_targets: PredicateNarrowingTargets::default(),
673 reachability_constraints: ReachabilityConstraintsBuilder::default().build(),
674 narrowing_constraints: NarrowingConstraintsBuilder::default().build(),
675 });
676
677static ALWAYS_UNBOUND_BINDINGS: LazyLock<Bindings> =
678 LazyLock::new(|| Bindings::unbound(ScopedReachabilityConstraintId::ALWAYS_TRUE));
679
680static ALWAYS_UNDECLARED_DECLARATIONS: LazyLock<Declarations> =
681 LazyLock::new(|| Declarations::undeclared(ScopedReachabilityConstraintId::ALWAYS_TRUE));
682
683#[derive(Clone, Copy, Debug, PartialEq, Eq, get_size2::GetSize, salsa::SalsaValue)]
685enum DefinitionEntry<'db> {
686 DeclarationPart(Definition<'db>),
689 Unused(Definition<'db>),
691 Used(Definition<'db>),
692 Undefined,
693 Deleted,
694}
695
696impl<'db> DefinitionEntry<'db> {
697 fn state(self) -> DefinitionState<'db> {
698 match self {
699 Self::DeclarationPart(definition)
700 | Self::Unused(definition)
701 | Self::Used(definition) => DefinitionState::Defined(definition),
702 Self::Undefined => DefinitionState::Undefined,
703 Self::Deleted => DefinitionState::Deleted,
704 }
705 }
706}
707
708static_assertions::assert_eq_size!(DefinitionEntry<'static>, DefinitionState<'static>);
709
710#[derive(Debug, PartialEq, Eq, get_size2::GetSize, salsa::SalsaValue)]
712struct RetainedDefinitions<'db> {
713 states: Box<[DefinitionEntry<'db>]>,
714}
715
716impl<'db> RetainedDefinitions<'db> {
717 fn new(states: IndexVec<ScopedDefinitionId, DefinitionEntry<'db>>) -> Self {
718 let mut states = states.into_iter();
719
720 let unbound_state = states.next();
721 debug_assert_eq!(unbound_state, Some(DefinitionEntry::Undefined));
722
723 Self {
724 states: states.collect(),
725 }
726 }
727
728 #[inline]
729 fn get(&self, id: ScopedDefinitionId) -> DefinitionEntry<'db> {
730 let index = id.index();
731 if index == 0 {
732 DefinitionEntry::Undefined
733 } else {
734 self.states[index - 1]
735 }
736 }
737
738 fn iter_enumerated(
739 &self,
740 ) -> impl Iterator<Item = (ScopedDefinitionId, DefinitionEntry<'db>)> + '_ {
741 self.states
742 .iter()
743 .copied()
744 .enumerate()
745 .map(|(index, entry)| (ScopedDefinitionId::new(index + 1), entry))
746 }
747}
748
749#[derive(Debug, PartialEq, Eq, get_size2::GetSize, salsa::SalsaValue)]
751pub struct UseDefMap<'db> {
752 all_definitions: RetainedDefinitions<'db>,
755
756 constraint_tables: Option<Box<ConstraintTables<'db>>>,
759
760 interned_bindings: RetainedBindings,
762 interned_declarations: RetainedDeclarations,
764
765 range_reachability: Box<[(TextRange, RangeInfo)]>,
769
770 definitions_by_definition: FrozenMap<
788 Definition<'db>,
789 DefinitionsAtDefinition<InternedBindingsId, InternedDeclarationsId>,
790 >,
791
792 symbol_states: FrozenIndexVec<ScopedSymbolId, RetainedPlaceStates<InternedPlaceStateId>>,
794
795 extra: Option<Box<UseDefMapExtra>>,
797
798 end_of_scope_reachability: ScopedReachabilityConstraintId,
816}
817
818#[derive(Debug, Copy, Clone, PartialEq, Eq, get_size2::GetSize)]
820struct RangeInfo {
821 reachability: ScopedReachabilityConstraintId,
822 in_type_checking_block: bool,
823}
824
825impl Default for RangeInfo {
826 fn default() -> Self {
827 Self {
828 reachability: ScopedReachabilityConstraintId::ALWAYS_TRUE,
829 in_type_checking_block: false,
830 }
831 }
832}
833
834#[derive(Debug, PartialEq, Eq, get_size2::GetSize)]
835struct MultiBindingsByUse(ThinVec<(ScopedUseId, Box<[Bindings]>)>);
836
837impl MultiBindingsByUse {
838 fn from_map(map: FxHashMap<ScopedUseId, Vec<Bindings>>) -> Self {
839 let mut entries = map
840 .into_iter()
841 .map(|(use_id, bindings)| (use_id, bindings.into_boxed_slice()))
842 .collect::<Vec<_>>();
843 entries.sort_unstable_by_key(|(use_id, _)| *use_id);
844 Self(entries.into_iter().collect())
845 }
846
847 fn get(&self, use_id: ScopedUseId) -> Option<&[Bindings]> {
848 self.0
849 .binary_search_by_key(&use_id, |(candidate, _)| *candidate)
850 .ok()
851 .map(|index| self.0[index].1.as_ref())
852 }
853}
854
855pub enum ApplicableConstraints<'map, 'db> {
856 UnboundBinding(NarrowingEvaluator<'map, 'db>),
857 ConstrainedBindings(BindingWithConstraintsIterator<'map, 'db>),
858}
859
860impl<'db> UseDefMap<'db> {
861 fn constraint_tables(&self) -> &ConstraintTables<'db> {
862 self.constraint_tables
863 .as_deref()
864 .map_or(&EMPTY_CONSTRAINT_TABLES, |tables| tables)
865 }
866
867 fn extra(&self) -> &UseDefMapExtra {
868 self.extra
869 .as_deref()
870 .expect("extra use-def data should have been retained")
871 }
872
873 pub fn loop_header(&self, id: LoopHeaderId) -> &LoopHeader {
874 &self.extra().loop_headers[id]
875 }
876
877 pub fn reachability_constraints(&self) -> &ReachabilityConstraints {
878 &self.constraint_tables().reachability_constraints
879 }
880
881 pub fn predicates(&self) -> &Predicates<'db> {
882 &self.constraint_tables().predicates
883 }
884
885 pub fn range_reachability(
886 &self,
887 ) -> impl Iterator<Item = (TextRange, ScopedReachabilityConstraintId)> + '_ {
888 self.range_reachability
889 .iter()
890 .map(|&(range, RangeInfo { reachability, .. })| (range, reachability))
891 }
892
893 pub fn end_of_scope_reachability(&self) -> ScopedReachabilityConstraintId {
894 self.end_of_scope_reachability
895 }
896
897 pub fn definitions_with_usage(
902 &self,
903 ) -> impl Iterator<Item = (ScopedDefinitionId, Definition<'db>, bool)> + '_ {
904 self.all_definitions
905 .iter_enumerated()
906 .filter_map(|(id, entry)| match entry {
907 DefinitionEntry::Unused(definition) => Some((id, definition, false)),
908 DefinitionEntry::Used(definition) => Some((id, definition, true)),
909 DefinitionEntry::DeclarationPart(_)
910 | DefinitionEntry::Undefined
911 | DefinitionEntry::Deleted => None,
912 })
913 }
914
915 pub fn bindings_at_use(&self, use_id: ScopedUseId) -> BindingWithConstraintsIterator<'_, 'db> {
916 let bindings_id = self.extra().bindings_by_use[use_id];
917 self.bindings_iterator(
918 &self.interned_bindings[bindings_id],
919 BoundnessAnalysis::BasedOnUnboundVisibility,
920 )
921 }
922
923 pub fn multi_bindings_at_use(
924 &self,
925 use_id: ScopedUseId,
926 ) -> impl Iterator<Item = BindingWithConstraintsIterator<'_, 'db>> {
927 self.extra
928 .as_deref()
929 .and_then(|extra| extra.multi_bindings_by_use.get(use_id))
930 .map(|member_bindings| {
931 member_bindings.iter().map(|bindings| {
932 self.bindings_iterator(
933 bindings.as_slice(),
934 BoundnessAnalysis::BasedOnUnboundVisibility,
935 )
936 })
937 })
938 .into_iter()
939 .flatten()
940 }
941
942 pub fn applicable_constraints(
943 &self,
944 constraint_key: ConstraintKey,
945 enclosing_scope: FileScopeId,
946 expr: PlaceExprRef,
947 index: &'db SemanticIndex,
948 ) -> ApplicableConstraints<'_, 'db> {
949 match constraint_key {
950 ConstraintKey::NarrowingConstraint(constraint) => {
951 ApplicableConstraints::UnboundBinding(NarrowingEvaluator {
952 constraint,
953 constraint_tables: self.constraint_tables(),
954 })
955 }
956 ConstraintKey::NestedScope(nested_scope) => {
957 let EnclosingSnapshotResult::FoundBindings(bindings) =
958 index.enclosing_snapshot(enclosing_scope, expr, nested_scope)
959 else {
960 unreachable!(
961 "The result of `SemanticIndex::eager_snapshot` must be `FoundBindings`"
962 )
963 };
964 ApplicableConstraints::ConstrainedBindings(bindings)
965 }
966 ConstraintKey::UseId(use_id) => {
967 ApplicableConstraints::ConstrainedBindings(self.bindings_at_use(use_id))
968 }
969 }
970 }
971
972 pub fn definition(&self, id: ScopedDefinitionId) -> DefinitionState<'db> {
973 self.all_definitions.get(id).state()
974 }
975
976 pub fn narrowing_evaluator(
977 &self,
978 constraint: ScopedNarrowingConstraint,
979 ) -> NarrowingEvaluator<'_, 'db> {
980 NarrowingEvaluator {
981 constraint,
982 constraint_tables: self.constraint_tables(),
983 }
984 }
985
986 pub(crate) fn is_range_in_type_checking_block(&self, range: TextRange) -> bool {
987 self.range_reachability
988 .iter()
989 .take_while(|(entry_range, _)| entry_range.start() <= range.start())
990 .any(|&(entry_range, block)| {
991 block.in_type_checking_block && entry_range.contains_range(range)
992 })
993 }
994 pub fn end_of_scope_bindings(
995 &self,
996 place: ScopedPlaceId,
997 ) -> BindingWithConstraintsIterator<'_, 'db> {
998 match place {
999 ScopedPlaceId::Symbol(symbol) => self.end_of_scope_symbol_bindings(symbol),
1000 ScopedPlaceId::Member(member) => self.end_of_scope_member_bindings(member),
1001 }
1002 }
1003
1004 pub fn end_of_scope_symbol_bindings(
1005 &self,
1006 symbol: ScopedSymbolId,
1007 ) -> BindingWithConstraintsIterator<'_, 'db> {
1008 let place_state_id = self.symbol_states[symbol].end_of_scope;
1009 self.bindings_iterator(
1010 &self.interned_bindings[place_state_id.bindings_id()],
1011 BoundnessAnalysis::BasedOnUnboundVisibility,
1012 )
1013 }
1014
1015 fn end_of_scope_member_bindings(
1016 &self,
1017 member: ScopedMemberId,
1018 ) -> BindingWithConstraintsIterator<'_, 'db> {
1019 let place_state_id = self.extra().member_states[member].end_of_scope;
1020 self.bindings_iterator(
1021 &self.interned_bindings[place_state_id.bindings_id()],
1022 BoundnessAnalysis::BasedOnUnboundVisibility,
1023 )
1024 }
1025
1026 pub fn reachable_bindings(
1027 &self,
1028 place: ScopedPlaceId,
1029 ) -> BindingWithConstraintsIterator<'_, 'db> {
1030 match place {
1031 ScopedPlaceId::Symbol(symbol) => self.reachable_symbol_bindings(symbol),
1032 ScopedPlaceId::Member(member) => self.reachable_member_bindings(member),
1033 }
1034 }
1035
1036 pub fn reachable_symbol_bindings(
1037 &self,
1038 symbol: ScopedSymbolId,
1039 ) -> BindingWithConstraintsIterator<'_, 'db> {
1040 let place_state_id = self.symbol_states[symbol].reachable;
1041 let bindings = &self.interned_bindings[place_state_id.bindings_id()];
1042 self.bindings_iterator(bindings, BoundnessAnalysis::AssumeBound)
1043 }
1044
1045 pub fn reachable_member_bindings(
1046 &self,
1047 member: ScopedMemberId,
1048 ) -> BindingWithConstraintsIterator<'_, 'db> {
1049 let place_state_id = self.extra().member_states[member].reachable;
1050 let bindings = &self.interned_bindings[place_state_id.bindings_id()];
1051 self.bindings_iterator(bindings, BoundnessAnalysis::AssumeBound)
1052 }
1053
1054 pub(crate) fn enclosing_snapshot(
1055 &self,
1056 snapshot_id: ScopedEnclosingSnapshotId,
1057 nested_laziness: ScopeLaziness,
1058 ) -> EnclosingSnapshotResult<'_, 'db> {
1059 let boundness_analysis = if nested_laziness.is_eager() {
1060 BoundnessAnalysis::BasedOnUnboundVisibility
1061 } else {
1062 BoundnessAnalysis::AssumeBound
1064 };
1065
1066 let Some(extra) = self.extra.as_deref() else {
1067 return EnclosingSnapshotResult::NotFound;
1068 };
1069
1070 match extra.enclosing_snapshots.get(snapshot_id) {
1071 Some(InternedEnclosingSnapshotId::Constraint(constraint)) => {
1072 EnclosingSnapshotResult::FoundConstraint(*constraint)
1073 }
1074 Some(InternedEnclosingSnapshotId::Bindings(bindings_id)) => {
1075 EnclosingSnapshotResult::FoundBindings(
1076 self.bindings_iterator(
1077 &self.interned_bindings[*bindings_id],
1078 boundness_analysis,
1079 ),
1080 )
1081 }
1082 None => EnclosingSnapshotResult::NotFound,
1083 }
1084 }
1085
1086 pub fn bindings_at_definition(
1087 &self,
1088 definition: Definition<'db>,
1089 ) -> BindingWithConstraintsIterator<'_, 'db> {
1090 let bindings = self.definitions_by_definition.get(&definition).map_or_else(
1091 || ALWAYS_UNBOUND_BINDINGS.as_slice(),
1092 |definitions| &self.interned_bindings[definitions.bindings],
1093 );
1094 self.bindings_iterator(bindings, BoundnessAnalysis::BasedOnUnboundVisibility)
1095 }
1096
1097 pub fn declarations_at_binding(
1098 &self,
1099 binding: Definition<'db>,
1100 ) -> DeclarationsIterator<'_, 'db> {
1101 let declarations = self.definitions_by_definition.get(&binding).map_or_else(
1102 || ALWAYS_UNDECLARED_DECLARATIONS.as_slice(),
1103 |definitions| {
1104 &self.interned_declarations[definitions
1105 .declarations
1106 .expect("binding definition should have retained declarations")]
1107 },
1108 );
1109 self.declarations_iterator(declarations, BoundnessAnalysis::BasedOnUnboundVisibility)
1110 }
1111
1112 pub fn end_of_scope_declarations<'map>(
1113 &'map self,
1114 place: ScopedPlaceId,
1115 ) -> DeclarationsIterator<'map, 'db> {
1116 match place {
1117 ScopedPlaceId::Symbol(symbol) => self.end_of_scope_symbol_declarations(symbol),
1118 ScopedPlaceId::Member(member) => self.end_of_scope_member_declarations(member),
1119 }
1120 }
1121
1122 pub fn end_of_scope_symbol_declarations<'map>(
1123 &'map self,
1124 symbol: ScopedSymbolId,
1125 ) -> DeclarationsIterator<'map, 'db> {
1126 let place_state_id = self.symbol_states[symbol].end_of_scope;
1127 let declarations = &self.interned_declarations[place_state_id.declarations_id()];
1128 self.declarations_iterator(declarations, BoundnessAnalysis::BasedOnUnboundVisibility)
1129 }
1130
1131 fn end_of_scope_member_declarations<'map>(
1132 &'map self,
1133 member: ScopedMemberId,
1134 ) -> DeclarationsIterator<'map, 'db> {
1135 let place_state_id = self.extra().member_states[member].end_of_scope;
1136 let declarations = &self.interned_declarations[place_state_id.declarations_id()];
1137 self.declarations_iterator(declarations, BoundnessAnalysis::BasedOnUnboundVisibility)
1138 }
1139
1140 pub fn reachable_symbol_declarations(
1141 &self,
1142 symbol: ScopedSymbolId,
1143 ) -> DeclarationsIterator<'_, 'db> {
1144 let place_state_id = self.symbol_states[symbol].reachable;
1145 let declarations = &self.interned_declarations[place_state_id.declarations_id()];
1146 self.declarations_iterator(declarations, BoundnessAnalysis::AssumeBound)
1147 }
1148
1149 pub fn reachable_member_declarations(
1150 &self,
1151 member: ScopedMemberId,
1152 ) -> DeclarationsIterator<'_, 'db> {
1153 let place_state_id = self.extra().member_states[member].reachable;
1154 let declarations = &self.interned_declarations[place_state_id.declarations_id()];
1155 self.declarations_iterator(declarations, BoundnessAnalysis::AssumeBound)
1156 }
1157
1158 pub fn reachable_declarations(&self, place: ScopedPlaceId) -> DeclarationsIterator<'_, 'db> {
1159 match place {
1160 ScopedPlaceId::Symbol(symbol) => self.reachable_symbol_declarations(symbol),
1161 ScopedPlaceId::Member(member) => self.reachable_member_declarations(member),
1162 }
1163 }
1164
1165 pub fn all_end_of_scope_symbol_declarations<'map>(
1166 &'map self,
1167 ) -> impl Iterator<Item = (ScopedSymbolId, DeclarationsIterator<'map, 'db>)> + 'map {
1168 self.symbol_states
1169 .indices()
1170 .map(|symbol_id| (symbol_id, self.end_of_scope_symbol_declarations(symbol_id)))
1171 }
1172
1173 pub fn all_end_of_scope_symbol_bindings<'map>(
1174 &'map self,
1175 ) -> impl Iterator<Item = (ScopedSymbolId, BindingWithConstraintsIterator<'map, 'db>)> + 'map
1176 {
1177 self.symbol_states
1178 .indices()
1179 .map(|symbol_id| (symbol_id, self.end_of_scope_symbol_bindings(symbol_id)))
1180 }
1181
1182 pub fn all_reachable_symbols<'map>(
1183 &'map self,
1184 ) -> impl Iterator<
1185 Item = (
1186 ScopedSymbolId,
1187 DeclarationsIterator<'map, 'db>,
1188 BindingWithConstraintsIterator<'map, 'db>,
1189 ),
1190 > + 'map {
1191 self.symbol_states.iter_enumerated().map(
1192 |(symbol_id, RetainedPlaceStates { reachable, .. })| {
1193 let declarations = self.declarations_iterator(
1194 &self.interned_declarations[reachable.declarations_id()],
1195 BoundnessAnalysis::AssumeBound,
1196 );
1197 let bindings = self.bindings_iterator(
1198 &self.interned_bindings[reachable.bindings_id()],
1199 BoundnessAnalysis::AssumeBound,
1200 );
1201 (symbol_id, declarations, bindings)
1202 },
1203 )
1204 }
1205
1206 fn bindings_iterator<'map>(
1207 &'map self,
1208 bindings: &'map [LiveBinding],
1209 boundness_analysis: BoundnessAnalysis,
1210 ) -> BindingWithConstraintsIterator<'map, 'db> {
1211 BindingWithConstraintsIterator {
1212 all_definitions: &self.all_definitions,
1213 constraint_tables: self.constraint_tables(),
1214 boundness_analysis,
1215 inner: bindings.iter(),
1216 }
1217 }
1218
1219 fn declarations_iterator<'map>(
1220 &'map self,
1221 declarations: &'map [LiveDeclaration],
1222 boundness_analysis: BoundnessAnalysis,
1223 ) -> DeclarationsIterator<'map, 'db> {
1224 DeclarationsIterator {
1225 all_definitions: &self.all_definitions,
1226 constraint_tables: self.constraint_tables(),
1227 boundness_analysis,
1228 inner: declarations.iter(),
1229 }
1230 }
1231}
1232
1233#[newtype_index]
1242#[derive(get_size2::GetSize)]
1243pub(crate) struct ScopedEnclosingSnapshotId;
1244
1245#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, get_size2::GetSize)]
1246pub(crate) struct EnclosingSnapshotKey {
1247 pub(crate) enclosing_scope: FileScopeId,
1249 pub(crate) enclosing_place: ScopedPlaceId,
1251 pub(crate) nested_scope: FileScopeId,
1253 pub(crate) nested_laziness: ScopeLaziness,
1255}
1256
1257type EnclosingSnapshots = IndexVec<ScopedEnclosingSnapshotId, EnclosingSnapshot>;
1262
1263#[derive(Clone, Debug)]
1264pub struct BindingWithConstraintsIterator<'map, 'db> {
1265 all_definitions: &'map RetainedDefinitions<'db>,
1266 constraint_tables: &'map ConstraintTables<'db>,
1267 boundness_analysis: BoundnessAnalysis,
1268 inner: LiveBindingsIterator<'map>,
1269}
1270
1271impl<'map, 'db> BindingWithConstraintsIterator<'map, 'db> {
1272 pub const fn predicates(&self) -> &'map Predicates<'db> {
1273 &self.constraint_tables.predicates
1274 }
1275
1276 pub const fn reachability_constraints(&self) -> &'map ReachabilityConstraints {
1277 &self.constraint_tables.reachability_constraints
1278 }
1279
1280 pub const fn boundness_analysis(&self) -> BoundnessAnalysis {
1281 self.boundness_analysis
1282 }
1283}
1284
1285impl<'map, 'db> Iterator for BindingWithConstraintsIterator<'map, 'db> {
1286 type Item = BindingWithConstraints<'map, 'db>;
1287
1288 fn next(&mut self) -> Option<Self::Item> {
1289 self.inner
1290 .next()
1291 .map(|live_binding| BindingWithConstraints {
1292 binding: self.all_definitions.get(live_binding.binding()).state(),
1293 binding_order: live_binding.binding(),
1294 narrowing_constraint: NarrowingEvaluator {
1295 constraint: live_binding.narrowing_constraint(),
1296 constraint_tables: self.constraint_tables,
1297 },
1298 reachability_constraint: live_binding.reachability_constraint(),
1299 })
1300 }
1301}
1302
1303impl std::iter::FusedIterator for BindingWithConstraintsIterator<'_, '_> {}
1304
1305pub struct BindingWithConstraints<'map, 'db> {
1306 pub binding: DefinitionState<'db>,
1307 pub binding_order: ScopedDefinitionId,
1309 pub narrowing_constraint: NarrowingEvaluator<'map, 'db>,
1310 pub reachability_constraint: ScopedReachabilityConstraintId,
1311}
1312
1313pub struct NarrowingEvaluator<'map, 'db> {
1314 constraint: ScopedNarrowingConstraint,
1315 constraint_tables: &'map ConstraintTables<'db>,
1316}
1317
1318impl<'map, 'db> NarrowingEvaluator<'map, 'db> {
1319 pub fn constraint(&self) -> ScopedNarrowingConstraint {
1320 self.constraint
1321 }
1322
1323 pub fn predicates(&self) -> &'map Predicates<'db> {
1324 &self.constraint_tables.predicates
1325 }
1326
1327 pub fn predicate_narrowing_targets(&self) -> &'map PredicateNarrowingTargets {
1328 &self.constraint_tables.predicate_narrowing_targets
1329 }
1330
1331 pub fn narrowing_constraints(&self) -> &'map NarrowingConstraints {
1332 &self.constraint_tables.narrowing_constraints
1333 }
1334}
1335
1336#[derive(Clone)]
1337pub struct DeclarationsIterator<'map, 'db> {
1338 all_definitions: &'map RetainedDefinitions<'db>,
1339 constraint_tables: &'map ConstraintTables<'db>,
1340 boundness_analysis: BoundnessAnalysis,
1341 inner: LiveDeclarationsIterator<'map>,
1342}
1343
1344impl<'map, 'db> DeclarationsIterator<'map, 'db> {
1345 pub const fn predicates(&self) -> &'map Predicates<'db> {
1346 &self.constraint_tables.predicates
1347 }
1348
1349 pub const fn reachability_constraints(&self) -> &'map ReachabilityConstraints {
1350 &self.constraint_tables.reachability_constraints
1351 }
1352
1353 pub const fn boundness_analysis(&self) -> BoundnessAnalysis {
1354 self.boundness_analysis
1355 }
1356}
1357
1358#[derive(Debug, Clone)]
1359pub struct DeclarationWithConstraint<'db> {
1360 pub declaration: DefinitionState<'db>,
1361 pub declaration_order: ScopedDefinitionId,
1363 pub reachability_constraint: ScopedReachabilityConstraintId,
1364}
1365
1366impl<'db> Iterator for DeclarationsIterator<'_, 'db> {
1367 type Item = DeclarationWithConstraint<'db>;
1368
1369 fn next(&mut self) -> Option<Self::Item> {
1370 self.inner.next().map(
1371 |LiveDeclaration {
1372 declaration,
1373 reachability_constraint,
1374 }| {
1375 DeclarationWithConstraint {
1376 declaration: self.all_definitions.get(*declaration).state(),
1377 declaration_order: *declaration,
1378 reachability_constraint: *reachability_constraint,
1379 }
1380 },
1381 )
1382 }
1383}
1384
1385impl std::iter::FusedIterator for DeclarationsIterator<'_, '_> {}
1386
1387#[derive(Clone, Debug, PartialEq, Eq, Hash, get_size2::GetSize)]
1388struct ReachableDefinitions {
1389 bindings: Bindings,
1390 declarations: Declarations,
1391}
1392
1393#[derive(Clone, Debug)]
1395pub(super) struct FlowSnapshot {
1396 symbol_states: IndexVec<ScopedSymbolId, PendingPlaceState>,
1397 member_states: IndexVec<ScopedMemberId, PendingPlaceState>,
1398 reachability: ScopedReachabilityConstraintId,
1399 checkpoint_flow: ScopedReachabilityConstraintId,
1400 checkpoint_state: ExceptionCheckpointSnapshot,
1401 pending_reachability: PendingReachabilityId,
1402}
1403
1404impl FlowSnapshot {
1405 pub(super) fn is_always_unreachable(&self) -> bool {
1406 self.reachability == ScopedReachabilityConstraintId::ALWAYS_FALSE
1407 }
1408}
1409
1410#[newtype_index]
1412struct PendingReachabilityId;
1413
1414#[derive(Debug)]
1415struct PendingReachabilityConstraint {
1416 parent: PendingReachabilityId,
1417 reachability_constraint: ScopedReachabilityConstraintId,
1418 narrowing_constraint: ScopedNarrowingConstraint,
1419}
1420
1421#[derive(Debug)]
1426struct PendingReachability {
1427 constraints: IndexVec<PendingReachabilityId, PendingReachabilityConstraint>,
1428 current: PendingReachabilityId,
1429}
1430
1431impl Default for PendingReachability {
1432 fn default() -> Self {
1433 let mut constraints = IndexVec::new();
1434 let root = constraints.next_index();
1435 constraints.push(PendingReachabilityConstraint {
1436 parent: root,
1437 reachability_constraint: ScopedReachabilityConstraintId::ALWAYS_TRUE,
1438 narrowing_constraint: ScopedNarrowingConstraint::ALWAYS_TRUE,
1439 });
1440 Self {
1441 constraints,
1442 current: root,
1443 }
1444 }
1445}
1446
1447impl PendingReachability {
1448 fn push(
1449 &mut self,
1450 reachability_constraint: ScopedReachabilityConstraintId,
1451 narrowing_constraint: ScopedNarrowingConstraint,
1452 ) {
1453 self.current = self.constraints.push(PendingReachabilityConstraint {
1454 parent: self.current,
1455 reachability_constraint,
1456 narrowing_constraint,
1457 });
1458 }
1459
1460 fn materialize<'a>(
1465 &self,
1466 pending: &'a mut PendingPlaceState,
1467 target: PendingReachabilityId,
1468 narrowing_constraints: &mut NarrowingConstraintsBuilder,
1469 reachability_constraints: &mut ReachabilityConstraintsBuilder,
1470 ) -> &'a mut PlaceState {
1471 self.materialize_reachability(pending, target, reachability_constraints);
1472 self.materialize_narrowing(pending, target, narrowing_constraints);
1473
1474 Rc::make_mut(&mut pending.state)
1475 }
1476
1477 fn materialize_narrowing(
1478 &self,
1479 pending: &mut PendingPlaceState,
1480 target: PendingReachabilityId,
1481 narrowing_constraints: &mut NarrowingConstraintsBuilder,
1482 ) {
1483 if pending.narrowing != target {
1484 let mut unapplied = SmallVec::<[ScopedNarrowingConstraint; 4]>::new();
1485 let mut current = target;
1486 while current != pending.narrowing {
1487 let event = &self.constraints[current];
1488 if event.narrowing_constraint != ScopedNarrowingConstraint::ALWAYS_TRUE {
1489 unapplied.push(event.narrowing_constraint);
1490 }
1491 assert_ne!(
1492 current, event.parent,
1493 "pending narrowing must be an ancestor"
1494 );
1495 current = event.parent;
1496 }
1497
1498 if !unapplied.is_empty() {
1499 let state = Rc::make_mut(&mut pending.state);
1500 for constraint in unapplied.into_iter().rev() {
1501 state.record_narrowing_constraint(narrowing_constraints, constraint);
1502 }
1503 }
1504 pending.narrowing = target;
1505 }
1506 }
1507
1508 fn materialize_reachability<'a>(
1509 &self,
1510 pending: &'a mut PendingPlaceState,
1511 target: PendingReachabilityId,
1512 reachability_constraints: &mut ReachabilityConstraintsBuilder,
1513 ) -> &'a mut PlaceState {
1514 if pending.reachability != target {
1515 let mut unapplied = SmallVec::<[ScopedReachabilityConstraintId; 4]>::new();
1516 let mut current = target;
1517 while current != pending.reachability {
1518 let event = &self.constraints[current];
1519 unapplied.push(event.reachability_constraint);
1520 assert_ne!(
1521 current, event.parent,
1522 "pending reachability must be an ancestor"
1523 );
1524 current = event.parent;
1525 }
1526
1527 let state = Rc::make_mut(&mut pending.state);
1528 for constraint in unapplied.into_iter().rev() {
1529 state.record_reachability_constraint(reachability_constraints, constraint);
1530 }
1531 pending.reachability = target;
1532 }
1533
1534 Rc::make_mut(&mut pending.state)
1535 }
1536
1537 fn materialize_ref<'a>(
1543 &self,
1544 pending: &'a mut PendingPlaceState,
1545 target: PendingReachabilityId,
1546 narrowing_constraints: &mut NarrowingConstraintsBuilder,
1547 reachability_constraints: &mut ReachabilityConstraintsBuilder,
1548 ) -> &'a PlaceState {
1549 if pending.reachability != target || pending.narrowing != target {
1550 self.materialize(
1551 pending,
1552 target,
1553 narrowing_constraints,
1554 reachability_constraints,
1555 );
1556 }
1557 &pending.state
1558 }
1559
1560 fn materialize_ref_at_use<'a>(
1565 &self,
1566 pending: &'a mut PendingPlaceState,
1567 target: PendingReachabilityId,
1568 reachability_constraints: &mut ReachabilityConstraintsBuilder,
1569 ) -> &'a PlaceState {
1570 self.materialize_reachability(pending, target, reachability_constraints);
1571 &pending.state
1572 }
1573
1574 fn constraint_between(
1578 &self,
1579 ancestor: PendingReachabilityId,
1580 target: PendingReachabilityId,
1581 reachability_constraints: &mut ReachabilityConstraintsBuilder,
1582 ) -> ScopedReachabilityConstraintId {
1583 let mut constraint = ScopedReachabilityConstraintId::ALWAYS_TRUE;
1584 let mut current = target;
1585 while current != ancestor {
1586 let event = &self.constraints[current];
1587 constraint = reachability_constraints
1588 .add_and_constraint(constraint, event.reachability_constraint);
1589 assert_ne!(
1590 current, event.parent,
1591 "pending reachability must be an ancestor"
1592 );
1593 current = event.parent;
1594 }
1595 constraint
1596 }
1597
1598 fn narrowing_constraint_between(
1602 &self,
1603 ancestor: PendingReachabilityId,
1604 target: PendingReachabilityId,
1605 narrowing_constraints: &mut NarrowingConstraintsBuilder,
1606 ) -> ScopedNarrowingConstraint {
1607 let mut unapplied = SmallVec::<[ScopedNarrowingConstraint; 4]>::new();
1608 let mut current = target;
1609 while current != ancestor {
1610 let event = &self.constraints[current];
1611 if event.narrowing_constraint != ScopedNarrowingConstraint::ALWAYS_TRUE {
1612 unapplied.push(event.narrowing_constraint);
1613 }
1614 assert_ne!(
1615 current, event.parent,
1616 "pending narrowing must be an ancestor"
1617 );
1618 current = event.parent;
1619 }
1620
1621 let mut constraint = ScopedNarrowingConstraint::ALWAYS_TRUE;
1622 for pending in unapplied.into_iter().rev() {
1623 constraint = narrowing_constraints.add_and_constraint(constraint, pending);
1624 }
1625 constraint
1626 }
1627
1628 fn common_ancestor(
1630 &self,
1631 mut left: PendingReachabilityId,
1632 mut right: PendingReachabilityId,
1633 ) -> PendingReachabilityId {
1634 while left != right {
1635 if left.index() > right.index() {
1636 left = self.constraints[left].parent;
1637 } else {
1638 right = self.constraints[right].parent;
1639 }
1640 }
1641 left
1642 }
1643}
1644
1645#[derive(Clone, Debug)]
1647struct PendingPlaceState {
1648 state: Rc<PlaceState>,
1649 reachability: PendingReachabilityId,
1650 narrowing: PendingReachabilityId,
1651}
1652
1653impl PendingPlaceState {
1654 fn new(state: PlaceState, reachability: PendingReachabilityId) -> Self {
1655 Self {
1656 state: Rc::new(state),
1657 reachability,
1658 narrowing: reachability,
1659 }
1660 }
1661}
1662
1663fn pending_place_state_mut<'a>(
1664 place: ScopedPlaceId,
1665 symbol_states: &'a mut IndexVec<ScopedSymbolId, PendingPlaceState>,
1666 member_states: &'a mut IndexVec<ScopedMemberId, PendingPlaceState>,
1667) -> &'a mut PendingPlaceState {
1668 match place {
1669 ScopedPlaceId::Symbol(symbol) => &mut symbol_states[symbol],
1670 ScopedPlaceId::Member(member) => &mut member_states[member],
1671 }
1672}
1673
1674impl PendingReachability {
1675 fn merge_place_states<I: Idx>(
1681 &self,
1682 current_states: &mut IndexVec<I, PendingPlaceState>,
1683 branch_states: IndexVec<I, PendingPlaceState>,
1684 branch: PendingReachabilityId,
1685 branch_reachability: ScopedReachabilityConstraintId,
1686 narrowing_constraints: &mut NarrowingConstraintsBuilder,
1687 reachability_constraints: &mut ReachabilityConstraintsBuilder,
1688 ) {
1689 let branch_ancestor = self.common_ancestor(self.current, branch);
1690 let current_narrowing =
1691 self.narrowing_constraint_between(branch_ancestor, self.current, narrowing_constraints);
1692 let branch_narrowing =
1693 self.narrowing_constraint_between(branch_ancestor, branch, narrowing_constraints);
1694 let merged_narrowing =
1695 narrowing_constraints.add_or_constraint(current_narrowing, branch_narrowing);
1696 let mut branch_states = branch_states.into_iter();
1697 for current in current_states {
1698 let Some(mut branch_state) = branch_states.next() else {
1699 let current = self.materialize(
1700 current,
1701 self.current,
1702 narrowing_constraints,
1703 reachability_constraints,
1704 );
1705 current.merge(
1706 PlaceState::undefined(branch_reachability),
1707 narrowing_constraints,
1708 reachability_constraints,
1709 );
1710 continue;
1711 };
1712
1713 if current.reachability == branch_state.reachability
1717 && current.narrowing == branch_state.narrowing
1718 && Rc::ptr_eq(¤t.state, &branch_state.state)
1719 {
1720 if self.current == branch {
1721 continue;
1722 }
1723
1724 self.materialize_narrowing(current, branch_ancestor, narrowing_constraints);
1728 if merged_narrowing != ScopedNarrowingConstraint::ALWAYS_TRUE {
1729 Rc::make_mut(&mut current.state)
1730 .record_narrowing_constraint(narrowing_constraints, merged_narrowing);
1731 }
1732
1733 let current_constraint = self.constraint_between(
1734 current.reachability,
1735 self.current,
1736 reachability_constraints,
1737 );
1738 let branch_constraint = self.constraint_between(
1739 branch_state.reachability,
1740 branch,
1741 reachability_constraints,
1742 );
1743 let merged_constraint = reachability_constraints
1744 .add_or_constraint(current_constraint, branch_constraint);
1745 if merged_constraint != ScopedReachabilityConstraintId::ALWAYS_TRUE {
1746 Rc::make_mut(&mut current.state).record_reachability_constraint(
1747 reachability_constraints,
1748 merged_constraint,
1749 );
1750 }
1751 current.reachability = self.current;
1752 current.narrowing = self.current;
1753 continue;
1754 }
1755
1756 self.materialize(
1757 &mut branch_state,
1758 branch,
1759 narrowing_constraints,
1760 reachability_constraints,
1761 );
1762 let branch_state = Rc::unwrap_or_clone(branch_state.state);
1763 let current = self.materialize(
1764 current,
1765 self.current,
1766 narrowing_constraints,
1767 reachability_constraints,
1768 );
1769 current.merge(
1770 branch_state,
1771 narrowing_constraints,
1772 reachability_constraints,
1773 );
1774 }
1775 }
1776}
1777
1778pub(super) struct SingleSymbolSnapshot {
1781 symbol_state: PlaceState,
1782 associated_member_states: FxHashMap<ScopedMemberId, PlaceState>,
1783}
1784
1785#[derive(Debug)]
1786pub(super) struct UseDefMapBuilder<'db> {
1787 all_definitions: IndexVec<ScopedDefinitionId, DefinitionEntry<'db>>,
1789
1790 predicates: PredicatesBuilder<'db>,
1792
1793 predicate_narrowing_targets: Vec<(ScopedPredicateId, ScopedPlaceId)>,
1795
1796 pub(super) reachability_constraints: ReachabilityConstraintsBuilder,
1798
1799 pub(super) narrowing_constraints: NarrowingConstraintsBuilder,
1801
1802 bindings_by_use: IndexVec<ScopedUseId, Bindings>,
1804
1805 multi_bindings_by_use: FxHashMap<ScopedUseId, Vec<Bindings>>,
1811
1812 pub(super) reachability: ScopedReachabilityConstraintId,
1815
1816 range_reachability: Vec<(TextRange, RangeInfo)>,
1819
1820 checkpoint_flow: ScopedReachabilityConstraintId,
1825
1826 checkpoint_state: ExceptionCheckpointState,
1828
1829 definitions_by_definition:
1832 FxHashMap<Definition<'db>, DefinitionsAtDefinition<Bindings, Declarations>>,
1833
1834 symbol_states: IndexVec<ScopedSymbolId, PendingPlaceState>,
1836
1837 member_states: IndexVec<ScopedMemberId, PendingPlaceState>,
1838
1839 pending_reachability: PendingReachability,
1842
1843 reachable_symbol_definitions: IndexVec<ScopedSymbolId, ReachableDefinitions>,
1845
1846 reachable_member_definitions: IndexVec<ScopedMemberId, ReachableDefinitions>,
1847
1848 enclosing_snapshots: EnclosingSnapshots,
1851
1852 loop_headers: IndexVec<LoopHeaderId, LoopHeader>,
1854
1855 is_class_scope: bool,
1857
1858 reachability_narrowing_enabled: bool,
1860}
1861
1862impl<'db> UseDefMapBuilder<'db> {
1863 pub(super) fn new(scope_kind: ScopeKind) -> Self {
1864 Self {
1865 all_definitions: IndexVec::from_iter([DefinitionEntry::Undefined]),
1866 predicates: PredicatesBuilder::default(),
1867 predicate_narrowing_targets: Vec::new(),
1868 reachability_constraints: ReachabilityConstraintsBuilder::default(),
1869 narrowing_constraints: NarrowingConstraintsBuilder::default(),
1870 bindings_by_use: IndexVec::new(),
1871 multi_bindings_by_use: FxHashMap::default(),
1872 reachability: ScopedReachabilityConstraintId::ALWAYS_TRUE,
1873 range_reachability: Vec::new(),
1874 checkpoint_flow: ScopedReachabilityConstraintId::ALWAYS_TRUE,
1875 checkpoint_state: ExceptionCheckpointState::default(),
1876 definitions_by_definition: FxHashMap::default(),
1877 symbol_states: IndexVec::new(),
1878 member_states: IndexVec::new(),
1879 pending_reachability: PendingReachability::default(),
1880 reachable_member_definitions: IndexVec::new(),
1881 reachable_symbol_definitions: IndexVec::new(),
1882 enclosing_snapshots: EnclosingSnapshots::default(),
1883 loop_headers: IndexVec::new(),
1884 is_class_scope: scope_kind.is_class(),
1885 reachability_narrowing_enabled: matches!(
1886 scope_kind,
1887 ScopeKind::Module | ScopeKind::Class | ScopeKind::Function | ScopeKind::Lambda
1888 ),
1889 }
1890 }
1891
1892 pub(super) fn reserve_loop_header(&mut self) -> LoopHeaderId {
1893 self.loop_headers.push(LoopHeader::new())
1894 }
1895
1896 pub(super) fn set_loop_header(&mut self, id: LoopHeaderId, header: LoopHeader) {
1897 self.loop_headers[id] = header;
1898 }
1899
1900 fn push_definition(&mut self, entry: DefinitionEntry<'db>) -> ScopedDefinitionId {
1901 self.checkpoint_state.record_binding_change();
1903 self.all_definitions.push(entry)
1904 }
1905
1906 pub(super) fn definition(&self, def_id: ScopedDefinitionId) -> DefinitionState<'db> {
1907 self.all_definitions[def_id].state()
1908 }
1909
1910 pub(super) fn mark_unreachable(&mut self) {
1911 self.record_reachability_constraint(ScopedReachabilityConstraintId::ALWAYS_FALSE);
1912 }
1913
1914 pub(super) fn add_place(&mut self, place: ScopedPlaceId) {
1915 self.checkpoint_state.record_binding_change();
1916 match place {
1917 ScopedPlaceId::Symbol(symbol) => {
1918 let new_place = self.symbol_states.push(PendingPlaceState::new(
1919 PlaceState::undefined(self.reachability),
1920 self.pending_reachability.current,
1921 ));
1922 debug_assert_eq!(symbol, new_place);
1923 let new_place = self
1924 .reachable_symbol_definitions
1925 .push(ReachableDefinitions {
1926 bindings: Bindings::unbound(self.reachability),
1927 declarations: Declarations::undeclared(self.reachability),
1928 });
1929 debug_assert_eq!(symbol, new_place);
1930 }
1931 ScopedPlaceId::Member(member) => {
1932 let new_place = self.member_states.push(PendingPlaceState::new(
1933 PlaceState::undefined(self.reachability),
1934 self.pending_reachability.current,
1935 ));
1936 debug_assert_eq!(member, new_place);
1937 let new_place = self
1938 .reachable_member_definitions
1939 .push(ReachableDefinitions {
1940 bindings: Bindings::unbound(self.reachability),
1941 declarations: Declarations::undeclared(self.reachability),
1942 });
1943 debug_assert_eq!(member, new_place);
1944 }
1945 }
1946 }
1947
1948 pub(super) fn next_definition_id(&self) -> ScopedDefinitionId {
1949 self.all_definitions.next_index()
1950 }
1951
1952 pub(super) fn exception_checkpoint_key(&self) -> ExceptionCheckpointKey {
1954 self.checkpoint_state
1955 .key((!self.reachability_constraints.is_saturated()).then_some(self.checkpoint_flow))
1956 }
1957
1958 pub(super) fn record_binding(
1959 &mut self,
1960 place: ScopedPlaceId,
1961 binding: Definition<'db>,
1962 previous_definitions: PreviousDefinitions,
1963 can_be_shadowed: FutureDefinitions,
1964 ) {
1965 let pending = self.pending_reachability.current;
1966 let def_id = self.push_definition(DefinitionEntry::Unused(binding));
1967 let place_state =
1968 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
1969 let place_state = self.pending_reachability.materialize(
1970 place_state,
1971 pending,
1972 &mut self.narrowing_constraints,
1973 &mut self.reachability_constraints,
1974 );
1975 let definitions_at_definition = DefinitionsAtDefinition {
1976 bindings: place_state.bindings().clone(),
1977 declarations: Some(place_state.declarations().clone()),
1978 };
1979
1980 place_state.record_binding(
1981 def_id,
1982 self.reachability,
1983 self.is_class_scope,
1984 place.is_symbol(),
1985 previous_definitions,
1986 can_be_shadowed,
1987 );
1988 self.definitions_by_definition
1989 .insert(binding, definitions_at_definition);
1990
1991 let bindings = match place {
1992 ScopedPlaceId::Symbol(symbol) => {
1993 &mut self.reachable_symbol_definitions[symbol].bindings
1994 }
1995 ScopedPlaceId::Member(member) => {
1996 &mut self.reachable_member_definitions[member].bindings
1997 }
1998 };
1999
2000 bindings.record_binding(
2001 def_id,
2002 self.reachability,
2003 self.is_class_scope,
2004 place.is_symbol(),
2005 PreviousDefinitions::AreKept,
2006 can_be_shadowed,
2007 );
2008 }
2009
2010 pub(crate) fn bindings_at_use(
2011 &self,
2012 use_id: ScopedUseId,
2013 ) -> impl Iterator<Item = &LiveBinding> {
2014 self.bindings_by_use[use_id].iter()
2015 }
2016
2017 pub(super) fn add_predicate(
2018 &mut self,
2019 predicate: PredicateOrLiteral<'db>,
2020 ) -> ScopedPredicateId {
2021 match predicate {
2022 PredicateOrLiteral::Predicate(predicate) => self.predicates.add_predicate(predicate),
2023 PredicateOrLiteral::Literal(true) => ScopedPredicateId::ALWAYS_TRUE,
2024 PredicateOrLiteral::Literal(false) => ScopedPredicateId::ALWAYS_FALSE,
2025 }
2026 }
2027
2028 pub(super) fn record_narrowing_constraint_for_places(
2030 &mut self,
2031 predicate: ScopedPredicateId,
2032 places: &PossiblyNarrowedPlaces,
2033 ) {
2034 if predicate == ScopedPredicateId::ALWAYS_TRUE
2035 || predicate == ScopedPredicateId::ALWAYS_FALSE
2036 {
2037 return;
2039 }
2040
2041 self.predicate_narrowing_targets
2042 .extend(places.iter().map(|place| (predicate, *place)));
2043
2044 let atom = self.narrowing_constraints.add_atom(predicate);
2045 self.record_narrowing_constraint_node_for_places(atom, places);
2046 }
2047
2048 pub(super) fn record_narrowing_constraint_for_bindings_at_use(
2051 &mut self,
2052 predicate: ScopedPredicateId,
2053 place: ScopedPlaceId,
2054 use_id: ScopedUseId,
2055 ) {
2056 if predicate == ScopedPredicateId::ALWAYS_TRUE
2057 || predicate == ScopedPredicateId::ALWAYS_FALSE
2058 {
2059 return;
2060 }
2061
2062 self.predicate_narrowing_targets.push((predicate, place));
2063
2064 let constraint = self.narrowing_constraints.add_atom(predicate);
2065 let pending = self.pending_reachability.current;
2066 let state =
2067 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
2068 let state = self.pending_reachability.materialize(
2069 state,
2070 pending,
2071 &mut self.narrowing_constraints,
2072 &mut self.reachability_constraints,
2073 );
2074 state.record_narrowing_constraint_for_bindings_at_use(
2075 &mut self.narrowing_constraints,
2076 constraint,
2077 &self.bindings_by_use[use_id],
2078 );
2079 }
2080
2081 pub(super) fn record_narrowing_constraint_for_bindings(
2083 &mut self,
2084 predicate: ScopedPredicateId,
2085 place: ScopedPlaceId,
2086 bindings: &[ScopedDefinitionId],
2087 ) {
2088 if predicate == ScopedPredicateId::ALWAYS_TRUE
2089 || predicate == ScopedPredicateId::ALWAYS_FALSE
2090 {
2091 return;
2092 }
2093
2094 self.predicate_narrowing_targets.push((predicate, place));
2095
2096 let constraint = self.narrowing_constraints.add_atom(predicate);
2097 let pending = self.pending_reachability.current;
2098 let state =
2099 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
2100 let state = self.pending_reachability.materialize(
2101 state,
2102 pending,
2103 &mut self.narrowing_constraints,
2104 &mut self.reachability_constraints,
2105 );
2106 state.record_narrowing_constraint_for_bindings(
2107 &mut self.narrowing_constraints,
2108 constraint,
2109 bindings,
2110 );
2111 }
2112
2113 pub(super) fn record_negated_narrowing_constraint_for_places(
2120 &mut self,
2121 predicate: ScopedPredicateId,
2122 places: &PossiblyNarrowedPlaces,
2123 ) {
2124 if predicate == ScopedPredicateId::ALWAYS_TRUE
2125 || predicate == ScopedPredicateId::ALWAYS_FALSE
2126 {
2127 return;
2128 }
2129
2130 let negated = self.narrowing_constraints.add_negated_atom(predicate);
2131 self.record_narrowing_constraint_node_for_places(negated, places);
2132 }
2133
2134 fn record_narrowing_constraint_node_for_places(
2136 &mut self,
2137 constraint: ScopedNarrowingConstraint,
2138 places: &PossiblyNarrowedPlaces,
2139 ) {
2140 let pending = self.pending_reachability.current;
2141 #[expect(
2142 clippy::iter_over_hash_type,
2143 reason = "the same constraint is recorded independently for each place"
2144 )]
2145 for place in places {
2146 match place {
2147 ScopedPlaceId::Symbol(symbol_id) => {
2148 if let Some(state) = self.symbol_states.get_mut(*symbol_id) {
2149 let state = self.pending_reachability.materialize(
2150 state,
2151 pending,
2152 &mut self.narrowing_constraints,
2153 &mut self.reachability_constraints,
2154 );
2155 state.record_narrowing_constraint(
2156 &mut self.narrowing_constraints,
2157 constraint,
2158 );
2159 }
2160 }
2161 ScopedPlaceId::Member(member_id) => {
2162 if let Some(state) = self.member_states.get_mut(*member_id) {
2163 let state = self.pending_reachability.materialize(
2164 state,
2165 pending,
2166 &mut self.narrowing_constraints,
2167 &mut self.reachability_constraints,
2168 );
2169 state.record_narrowing_constraint(
2170 &mut self.narrowing_constraints,
2171 constraint,
2172 );
2173 }
2174 }
2175 }
2176 }
2177 }
2178
2179 pub(super) fn single_symbol_snapshot(
2186 &mut self,
2187 symbol: ScopedSymbolId,
2188 associated_member_ids: &[ScopedMemberId],
2189 ) -> SingleSymbolSnapshot {
2190 let pending = self.pending_reachability.current;
2191 let symbol_state = self
2192 .pending_reachability
2193 .materialize_ref(
2194 &mut self.symbol_states[symbol],
2195 pending,
2196 &mut self.narrowing_constraints,
2197 &mut self.reachability_constraints,
2198 )
2199 .clone();
2200 let mut associated_member_states = FxHashMap::default();
2201 for &member_id in associated_member_ids {
2202 let state = self.pending_reachability.materialize_ref(
2203 &mut self.member_states[member_id],
2204 pending,
2205 &mut self.narrowing_constraints,
2206 &mut self.reachability_constraints,
2207 );
2208 associated_member_states.insert(member_id, state.clone());
2209 }
2210 SingleSymbolSnapshot {
2211 symbol_state,
2212 associated_member_states,
2213 }
2214 }
2215
2216 pub(super) fn record_and_negate_star_import_reachability_constraint(
2246 &mut self,
2247 reachability_id: ScopedReachabilityConstraintId,
2248 symbol: ScopedSymbolId,
2249 pre_definition: SingleSymbolSnapshot,
2250 ) {
2251 self.checkpoint_state.record_binding_change();
2252 let negated_reachability_id = self
2253 .reachability_constraints
2254 .add_not_constraint(reachability_id);
2255 let pending = self.pending_reachability.current;
2256
2257 let symbol_state = self.pending_reachability.materialize(
2258 &mut self.symbol_states[symbol],
2259 pending,
2260 &mut self.narrowing_constraints,
2261 &mut self.reachability_constraints,
2262 );
2263 let mut post_definition_state =
2264 std::mem::replace(symbol_state, pre_definition.symbol_state);
2265
2266 post_definition_state
2267 .record_reachability_constraint(&mut self.reachability_constraints, reachability_id);
2268
2269 symbol_state.record_reachability_constraint(
2270 &mut self.reachability_constraints,
2271 negated_reachability_id,
2272 );
2273
2274 symbol_state.merge(
2275 post_definition_state,
2276 &mut self.narrowing_constraints,
2277 &mut self.reachability_constraints,
2278 );
2279
2280 #[expect(
2282 clippy::iter_over_hash_type,
2283 reason = "associated member states are merged independently"
2284 )]
2285 for (member_id, pre_definition_member_state) in pre_definition.associated_member_states {
2286 let member_state = self.pending_reachability.materialize(
2287 &mut self.member_states[member_id],
2288 pending,
2289 &mut self.narrowing_constraints,
2290 &mut self.reachability_constraints,
2291 );
2292 let mut post_definition_state =
2293 std::mem::replace(member_state, pre_definition_member_state);
2294
2295 post_definition_state.record_reachability_constraint(
2296 &mut self.reachability_constraints,
2297 reachability_id,
2298 );
2299
2300 member_state.record_reachability_constraint(
2301 &mut self.reachability_constraints,
2302 negated_reachability_id,
2303 );
2304
2305 member_state.merge(
2306 post_definition_state,
2307 &mut self.narrowing_constraints,
2308 &mut self.reachability_constraints,
2309 );
2310 }
2311 }
2312
2313 pub(super) fn record_reachability_constraint(
2314 &mut self,
2315 reachability_constraint: ScopedReachabilityConstraintId,
2316 ) {
2317 self.checkpoint_flow = self
2318 .reachability_constraints
2319 .add_and_constraint(self.checkpoint_flow, reachability_constraint);
2320 let narrowing_constraint = if self.reachability_narrowing_enabled {
2321 self.reachability_constraints
2322 .narrowing_gate(reachability_constraint, &mut self.narrowing_constraints)
2323 } else {
2324 ScopedNarrowingConstraint::ALWAYS_TRUE
2325 };
2326 self.record_reachability_constraint_impl(reachability_constraint, narrowing_constraint);
2327 }
2328
2329 pub(super) fn record_non_terminal_call_constraints(
2334 &mut self,
2335 reachability_constraint: ScopedReachabilityConstraintId,
2336 narrowing_constraint: ScopedNarrowingConstraint,
2337 ) {
2338 self.checkpoint_state.record_call_gate();
2339 self.record_reachability_constraint_impl(reachability_constraint, narrowing_constraint);
2340 }
2341
2342 fn record_reachability_constraint_impl(
2343 &mut self,
2344 reachability_constraint: ScopedReachabilityConstraintId,
2345 narrowing_constraint: ScopedNarrowingConstraint,
2346 ) {
2347 self.reachability = self
2348 .reachability_constraints
2349 .add_and_constraint(self.reachability, reachability_constraint);
2350 self.pending_reachability
2351 .push(reachability_constraint, narrowing_constraint);
2352 }
2353
2354 pub(super) fn record_declaration(
2355 &mut self,
2356 place: ScopedPlaceId,
2357 declaration: Definition<'db>,
2358 ) {
2359 let def_id = self.push_definition(DefinitionEntry::Unused(declaration));
2360 let pending = self.pending_reachability.current;
2361 let place_state =
2362 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
2363 let place_state = self.pending_reachability.materialize(
2364 place_state,
2365 pending,
2366 &mut self.narrowing_constraints,
2367 &mut self.reachability_constraints,
2368 );
2369
2370 self.definitions_by_definition.insert(
2371 declaration,
2372 DefinitionsAtDefinition {
2373 bindings: place_state.bindings().clone(),
2374 declarations: None,
2375 },
2376 );
2377 place_state.record_declaration(def_id, self.reachability);
2378
2379 let definitions = match place {
2380 ScopedPlaceId::Symbol(symbol) => &mut self.reachable_symbol_definitions[symbol],
2381 ScopedPlaceId::Member(member) => &mut self.reachable_member_definitions[member],
2382 };
2383
2384 definitions.declarations.record_declaration(
2385 def_id,
2386 self.reachability,
2387 PreviousDefinitions::AreKept,
2388 );
2389 }
2390
2391 pub(super) fn record_combined_definition(
2396 &mut self,
2397 place: ScopedPlaceId,
2398 definition: Definition<'db>,
2399 part: DefinitionCategory,
2400 ) {
2401 let entry = if part.is_binding() {
2404 DefinitionEntry::Unused(definition)
2405 } else {
2406 DefinitionEntry::DeclarationPart(definition)
2407 };
2408 let def_id = self.push_definition(entry);
2409 let pending = self.pending_reachability.current;
2410 let place_state =
2411 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
2412 let place_state = self.pending_reachability.materialize(
2413 place_state,
2414 pending,
2415 &mut self.narrowing_constraints,
2416 &mut self.reachability_constraints,
2417 );
2418 let reachable_definitions = match place {
2419 ScopedPlaceId::Symbol(symbol) => &mut self.reachable_symbol_definitions[symbol],
2420 ScopedPlaceId::Member(member) => &mut self.reachable_member_definitions[member],
2421 };
2422
2423 if part.is_declaration() {
2424 place_state.record_declaration(def_id, self.reachability);
2425 reachable_definitions.declarations.record_declaration(
2426 def_id,
2427 self.reachability,
2428 PreviousDefinitions::AreKept,
2429 );
2430 }
2431 if part.is_binding() {
2432 place_state.record_binding(
2433 def_id,
2434 self.reachability,
2435 self.is_class_scope,
2436 place.is_symbol(),
2437 PreviousDefinitions::AreShadowed,
2438 FutureDefinitions::ShadowThisOne,
2439 );
2440 reachable_definitions.bindings.record_binding(
2441 def_id,
2442 self.reachability,
2443 self.is_class_scope,
2444 place.is_symbol(),
2445 PreviousDefinitions::AreKept,
2446 FutureDefinitions::ShadowThisOne,
2447 );
2448 }
2449 }
2450
2451 pub(super) fn delete_binding(&mut self, place: ScopedPlaceId) {
2452 let def_id = self.push_definition(DefinitionEntry::Deleted);
2453 let pending = self.pending_reachability.current;
2454 let place_state =
2455 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
2456 let place_state = self.pending_reachability.materialize(
2457 place_state,
2458 pending,
2459 &mut self.narrowing_constraints,
2460 &mut self.reachability_constraints,
2461 );
2462
2463 place_state.record_binding(
2464 def_id,
2465 self.reachability,
2466 self.is_class_scope,
2467 place.is_symbol(),
2468 PreviousDefinitions::AreShadowed,
2469 FutureDefinitions::ShadowThisOne,
2470 );
2471 }
2472
2473 pub(super) fn record_use(&mut self, place: ScopedPlaceId, use_id: ScopedUseId) {
2474 let pending = self.pending_reachability.current;
2475 let place_state =
2476 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
2477 let place_state = self.pending_reachability.materialize_ref_at_use(
2478 place_state,
2479 pending,
2480 &mut self.reachability_constraints,
2481 );
2482 let bindings = place_state.bindings().clone();
2483
2484 self.record_use_bindings(bindings, use_id);
2485 }
2486
2487 pub(super) fn record_multi_use(
2488 &mut self,
2489 places: impl Iterator<Item = ScopedPlaceId>,
2490 use_id: ScopedUseId,
2491 ) {
2492 let pending = self.pending_reachability.current;
2493 for place in places {
2494 let place_state =
2495 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
2496 let place_state = self.pending_reachability.materialize_ref_at_use(
2497 place_state,
2498 pending,
2499 &mut self.reachability_constraints,
2500 );
2501 let bindings = place_state.bindings().clone();
2502
2503 let binding_definition_ids = bindings.iter().map(LiveBinding::binding);
2504 self.mark_definition_ids_used(binding_definition_ids);
2505
2506 self.multi_bindings_by_use
2507 .entry(use_id)
2508 .or_default()
2509 .push(bindings);
2510 }
2511
2512 self.record_use_bindings(Bindings::default(), use_id);
2514 }
2515
2516 fn record_use_bindings(&mut self, bindings: Bindings, use_id: ScopedUseId) {
2517 let binding_definition_ids = bindings.iter().map(LiveBinding::binding);
2518 self.mark_definition_ids_used(binding_definition_ids);
2519
2520 let new_use = self.bindings_by_use.push(bindings);
2523 debug_assert_eq!(use_id, new_use);
2524 }
2525
2526 pub(super) fn symbol_binding_definition_ids(
2527 &self,
2528 symbol: ScopedSymbolId,
2529 ) -> impl Iterator<Item = ScopedDefinitionId> + '_ {
2530 self.symbol_states[symbol]
2531 .state
2532 .bindings()
2533 .iter()
2534 .map(LiveBinding::binding)
2535 }
2536
2537 pub(super) fn symbol_live_binding_status(
2543 &mut self,
2544 symbol: ScopedSymbolId,
2545 ) -> LiveBindingStatus {
2546 let mut has_binding = false;
2547 let mut has_unbound = false;
2548
2549 for binding in self.current_bindings(symbol.into()) {
2550 if binding.reachability_constraint() == ScopedReachabilityConstraintId::ALWAYS_FALSE {
2551 continue;
2552 }
2553
2554 if binding.binding().is_unbound() {
2555 has_unbound = true;
2556 } else {
2557 has_binding = true;
2558 }
2559 }
2560
2561 match (has_binding, has_unbound) {
2562 (true, true) => LiveBindingStatus::PossiblyBound,
2563 (true, false) => LiveBindingStatus::Bound,
2564 (false, _) => LiveBindingStatus::Unbound,
2565 }
2566 }
2567
2568 pub(super) fn mark_binding_definitions_used(
2569 &mut self,
2570 binding_definition_ids: impl IntoIterator<Item = ScopedDefinitionId>,
2571 ) {
2572 self.mark_definition_ids_used(binding_definition_ids);
2573 }
2574
2575 pub(super) fn record_range_reachability(
2576 &mut self,
2577 range: TextRange,
2578 is_type_checking_block: bool,
2579 ) {
2580 let this_range_info = RangeInfo {
2581 reachability: self.reachability,
2582 in_type_checking_block: is_type_checking_block,
2583 };
2584
2585 if let Some((last_range, last_range_info)) = self.range_reachability.last_mut()
2589 && *last_range_info == this_range_info
2590 {
2591 *last_range = last_range.cover(range);
2592 return;
2593 }
2594 self.range_reachability.push((range, this_range_info));
2595 }
2596
2597 pub(super) fn snapshot_enclosing_state(
2598 &mut self,
2599 enclosing_place: ScopedPlaceId,
2600 enclosing_scope: ScopeKind,
2601 enclosing_place_expr: PlaceExprRef,
2602 is_parent_of_annotation_scope: bool,
2603 ) -> ScopedEnclosingSnapshotId {
2604 let pending = self.pending_reachability.current;
2605 let place_state = pending_place_state_mut(
2606 enclosing_place,
2607 &mut self.symbol_states,
2608 &mut self.member_states,
2609 );
2610 let bindings = self
2611 .pending_reachability
2612 .materialize_ref(
2613 place_state,
2614 pending,
2615 &mut self.narrowing_constraints,
2616 &mut self.reachability_constraints,
2617 )
2618 .bindings();
2619
2620 let is_class_symbol = enclosing_scope.is_class() && enclosing_place.is_symbol();
2621 let is_forwarding_symbol = enclosing_place_expr
2622 .as_symbol()
2623 .is_some_and(|symbol| symbol.is_global() || symbol.is_nonlocal());
2624 let stores_visible_bindings = enclosing_place_expr.is_bound()
2625 && bindings
2626 .iter()
2627 .any(|binding| !binding.binding().is_unbound());
2628 if (is_class_symbol && !is_parent_of_annotation_scope)
2637 || !enclosing_place_expr.is_bound()
2638 || (is_forwarding_symbol && !stores_visible_bindings)
2639 {
2640 self.enclosing_snapshots.push(EnclosingSnapshot::Constraint(
2641 bindings.unbound_narrowing_constraint(),
2642 ))
2643 } else {
2644 self.enclosing_snapshots
2645 .push(EnclosingSnapshot::Bindings(bindings.clone()))
2646 }
2647 }
2648
2649 pub(super) fn update_enclosing_snapshot(
2650 &mut self,
2651 snapshot_id: ScopedEnclosingSnapshotId,
2652 enclosing_symbol: ScopedSymbolId,
2653 ) {
2654 let pending = self.pending_reachability.current;
2655 let new_bindings = self
2656 .pending_reachability
2657 .materialize_ref(
2658 &mut self.symbol_states[enclosing_symbol],
2659 pending,
2660 &mut self.narrowing_constraints,
2661 &mut self.reachability_constraints,
2662 )
2663 .bindings()
2664 .clone();
2665 match self.enclosing_snapshots.get_mut(snapshot_id) {
2666 Some(EnclosingSnapshot::Bindings(bindings)) => {
2667 bindings.merge(
2668 new_bindings,
2669 &mut self.narrowing_constraints,
2670 &mut self.reachability_constraints,
2671 );
2672 }
2673 Some(EnclosingSnapshot::Constraint(constraint)) => {
2674 *constraint = ScopedNarrowingConstraint::ALWAYS_TRUE;
2675 }
2676 None => {}
2677 }
2678 }
2679
2680 fn mark_definition_ids_used(
2681 &mut self,
2682 definition_ids: impl IntoIterator<Item = ScopedDefinitionId>,
2683 ) {
2684 for definition_id in definition_ids {
2685 self.mark_definition_used(definition_id);
2686 }
2687 }
2688
2689 fn mark_definition_used(&mut self, definition_id: ScopedDefinitionId) {
2690 let entry = &mut self.all_definitions[definition_id];
2691 if let DefinitionEntry::Unused(definition) = *entry {
2692 *entry = DefinitionEntry::Used(definition);
2693 }
2694 }
2695
2696 pub(super) fn snapshot(&self) -> FlowSnapshot {
2698 FlowSnapshot {
2699 symbol_states: self.symbol_states.clone(),
2700 member_states: self.member_states.clone(),
2701 reachability: self.reachability,
2702 checkpoint_flow: self.checkpoint_flow,
2703 checkpoint_state: self.checkpoint_state.snapshot(),
2704 pending_reachability: self.pending_reachability.current,
2705 }
2706 }
2707
2708 pub(super) fn current_bindings(
2710 &mut self,
2711 place: ScopedPlaceId,
2712 ) -> impl Iterator<Item = LiveBinding> + '_ {
2713 let pending = self.pending_reachability.current;
2714 let place_state =
2715 pending_place_state_mut(place, &mut self.symbol_states, &mut self.member_states);
2716 let bindings = self
2717 .pending_reachability
2718 .materialize_ref(
2719 place_state,
2720 pending,
2721 &mut self.narrowing_constraints,
2722 &mut self.reachability_constraints,
2723 )
2724 .bindings();
2725
2726 bindings.iter().copied()
2727 }
2728
2729 pub(super) fn restore(&mut self, snapshot: FlowSnapshot) {
2731 self.checkpoint_state.restore(snapshot.checkpoint_state);
2732 let num_symbols = self.symbol_states.len();
2736 let num_members = self.member_states.len();
2737 debug_assert!(num_symbols >= snapshot.symbol_states.len());
2738
2739 self.symbol_states = snapshot.symbol_states;
2741 self.member_states = snapshot.member_states;
2742 self.reachability = snapshot.reachability;
2743 self.checkpoint_flow = snapshot.checkpoint_flow;
2744 self.pending_reachability.current = snapshot.pending_reachability;
2745
2746 let undefined = PendingPlaceState::new(
2750 PlaceState::undefined(self.reachability),
2751 self.pending_reachability.current,
2752 );
2753 self.symbol_states.resize(num_symbols, undefined.clone());
2754 self.member_states.resize(num_members, undefined);
2755 }
2756
2757 pub(super) fn merge(&mut self, snapshot: FlowSnapshot) {
2761 if snapshot.reachability == ScopedReachabilityConstraintId::ALWAYS_FALSE {
2769 return;
2770 }
2771 if self.reachability == ScopedReachabilityConstraintId::ALWAYS_FALSE {
2772 self.restore(snapshot);
2773 return;
2774 }
2775
2776 self.checkpoint_state.merge(snapshot.checkpoint_state);
2777
2778 debug_assert!(self.symbol_states.len() >= snapshot.symbol_states.len());
2782 debug_assert!(self.member_states.len() >= snapshot.member_states.len());
2783
2784 let branch = snapshot.pending_reachability;
2785 self.pending_reachability.merge_place_states(
2786 &mut self.symbol_states,
2787 snapshot.symbol_states,
2788 branch,
2789 snapshot.reachability,
2790 &mut self.narrowing_constraints,
2791 &mut self.reachability_constraints,
2792 );
2793 self.pending_reachability.merge_place_states(
2794 &mut self.member_states,
2795 snapshot.member_states,
2796 branch,
2797 snapshot.reachability,
2798 &mut self.narrowing_constraints,
2799 &mut self.reachability_constraints,
2800 );
2801
2802 self.reachability = self
2803 .reachability_constraints
2804 .add_or_constraint(self.reachability, snapshot.reachability);
2805 self.checkpoint_flow = self
2806 .reachability_constraints
2807 .add_or_constraint(self.checkpoint_flow, snapshot.checkpoint_flow);
2808 }
2809
2810 pub(super) fn finish(mut self: Box<Self>) -> UseDefMap<'db> {
2811 let pending = self.pending_reachability.current;
2812 for state in self
2813 .symbol_states
2814 .iter_mut()
2815 .chain(self.member_states.iter_mut())
2816 {
2817 self.pending_reachability.materialize_reachability(
2820 state,
2821 pending,
2822 &mut self.reachability_constraints,
2823 );
2824 }
2825
2826 let place_state_count = self.symbol_states.len()
2827 + self.member_states.len()
2828 + self.reachable_symbol_definitions.len()
2829 + self.reachable_member_definitions.len();
2830 let definitions_with_declarations_count = self
2831 .definitions_by_definition
2832 .values()
2833 .filter(|definitions| definitions.declarations.is_some())
2834 .count();
2835 let interned_bindings_capacity = self.definitions_by_definition.len()
2836 + self.bindings_by_use.len()
2837 + self.enclosing_snapshots.len()
2838 + place_state_count;
2839 let interned_declarations_capacity =
2840 definitions_with_declarations_count + place_state_count;
2841 let interned_ids_by_declarations_capacity =
2842 definitions_with_declarations_count + self.member_states.len();
2843 let mut place_state_interner = PlaceStateInterner::with_capacity(
2844 interned_bindings_capacity,
2845 interned_ids_by_declarations_capacity,
2846 interned_declarations_capacity,
2847 );
2848 let definitions_by_definition = Self::intern_definitions_by_definition(
2850 self.definitions_by_definition,
2851 &mut place_state_interner,
2852 );
2853 let bindings_by_use =
2854 Self::intern_bindings_by_use(self.bindings_by_use, &mut place_state_interner);
2855 let symbol_states = self
2856 .symbol_states
2857 .into_iter()
2858 .map(|state| Rc::unwrap_or_clone(state.state))
2859 .collect();
2860 let member_states = self
2861 .member_states
2862 .into_iter()
2863 .map(|state| Rc::unwrap_or_clone(state.state))
2864 .collect();
2865 let end_of_scope_symbols = Self::intern_place_states(
2866 symbol_states,
2867 PlaceState::into_parts,
2868 &mut place_state_interner,
2869 );
2870 let end_of_scope_members =
2871 Self::intern_end_of_scope_members(member_states, &mut place_state_interner);
2872 let reachable_definitions_by_symbol = Self::intern_place_states(
2873 self.reachable_symbol_definitions,
2874 |definitions| (definitions.bindings, definitions.declarations),
2875 &mut place_state_interner,
2876 );
2877 let reachable_definitions_by_member = Self::intern_place_states(
2878 self.reachable_member_definitions,
2879 |definitions| (definitions.bindings, definitions.declarations),
2880 &mut place_state_interner,
2881 );
2882 let enclosing_snapshots =
2883 Self::intern_enclosing_snapshots(self.enclosing_snapshots, &mut place_state_interner);
2884 let PlaceStateInterner {
2885 interned_bindings,
2886 interned_declarations,
2887 ..
2888 } = place_state_interner;
2889
2890 let interned_bindings = interned_bindings.finish(
2893 &mut self.narrowing_constraints,
2894 &mut self.reachability_constraints,
2895 );
2896 let interned_declarations =
2897 interned_declarations.finish(&mut self.reachability_constraints);
2898 for bindings in self.multi_bindings_by_use.values_mut().flatten() {
2899 bindings.finish(
2900 &mut self.narrowing_constraints,
2901 &mut self.reachability_constraints,
2902 );
2903 }
2904 self.range_reachability
2908 .retain(|(_, info)| *info != RangeInfo::default());
2909 for &(_, RangeInfo { reachability, .. }) in &self.range_reachability {
2910 self.reachability_constraints.mark_used(reachability);
2911 }
2912 for enclosing_snapshot in &enclosing_snapshots {
2913 if let InternedEnclosingSnapshotId::Constraint(constraint) = enclosing_snapshot {
2915 self.narrowing_constraints.mark_used(*constraint);
2916 }
2917 }
2918 self.reachability_constraints.mark_used(self.reachability);
2919 let symbol_states =
2920 Self::zip_place_states(end_of_scope_symbols, reachable_definitions_by_symbol);
2921 let member_states =
2922 Self::zip_place_states(end_of_scope_members, reachable_definitions_by_member);
2923 let multi_bindings_by_use = MultiBindingsByUse::from_map(self.multi_bindings_by_use);
2924 let loop_headers = self.loop_headers;
2925 let extra = (!bindings_by_use.is_empty()
2926 || !member_states.is_empty()
2927 || !enclosing_snapshots.is_empty()
2928 || !loop_headers.is_empty())
2929 .then(|| {
2930 Box::new(UseDefMapExtra {
2931 bindings_by_use: bindings_by_use.into(),
2932 multi_bindings_by_use,
2933 member_states,
2934 enclosing_snapshots: enclosing_snapshots.into(),
2935 loop_headers: loop_headers.into(),
2936 })
2937 });
2938 let predicates = self.predicates.build();
2939 let predicate_narrowing_targets =
2940 PredicateNarrowingTargets::from_entries(self.predicate_narrowing_targets);
2941 let reachability_constraints = self.reachability_constraints.build();
2942 let narrowing_constraints = self.narrowing_constraints.build();
2943 let constraint_tables = (!reachability_constraints.used_interiors().is_empty()
2944 || !narrowing_constraints.is_empty())
2945 .then(|| {
2946 Box::new(ConstraintTables {
2947 predicates,
2948 predicate_narrowing_targets,
2949 reachability_constraints,
2950 narrowing_constraints,
2951 })
2952 });
2953 let all_definitions = RetainedDefinitions::new(self.all_definitions);
2954
2955 UseDefMap {
2956 all_definitions,
2957 constraint_tables,
2958 interned_bindings,
2959 interned_declarations,
2960 range_reachability: self.range_reachability.into_boxed_slice(),
2961 symbol_states,
2962 definitions_by_definition,
2963 extra,
2964 end_of_scope_reachability: self.reachability,
2965 }
2966 }
2967
2968 fn zip_place_states<I: Idx, T>(
2969 end_of_scope: IndexVec<I, T>,
2970 reachable: IndexVec<I, T>,
2971 ) -> FrozenIndexVec<I, RetainedPlaceStates<T>> {
2972 assert_eq!(end_of_scope.len(), reachable.len());
2973
2974 end_of_scope
2975 .into_iter()
2976 .zip(reachable)
2977 .map(|(end_of_scope, reachable)| RetainedPlaceStates {
2978 end_of_scope,
2979 reachable,
2980 })
2981 .collect()
2982 }
2983
2984 fn intern_definitions_by_definition(
2985 definitions_by_definition: FxHashMap<
2986 Definition<'db>,
2987 DefinitionsAtDefinition<Bindings, Declarations>,
2988 >,
2989 place_state_interner: &mut PlaceStateInterner,
2990 ) -> FrozenMap<
2991 Definition<'db>,
2992 DefinitionsAtDefinition<InternedBindingsId, InternedDeclarationsId>,
2993 > {
2994 let mut interned_ids_by_definition = Vec::with_capacity(definitions_by_definition.len());
2995
2996 let mut definitions_by_definition =
2999 definitions_by_definition.into_iter().collect::<Vec<_>>();
3000 definitions_by_definition.sort_unstable_by_key(|(definition, _)| *definition);
3001
3002 for (
3003 definition,
3004 DefinitionsAtDefinition {
3005 bindings,
3006 declarations,
3007 },
3008 ) in definitions_by_definition
3009 {
3010 if bindings.is_always_unbound()
3012 && declarations
3013 .as_ref()
3014 .is_none_or(Declarations::is_always_undeclared)
3015 {
3016 continue;
3017 }
3018
3019 let bindings = place_state_interner.intern_bindings(&bindings);
3020 let declarations = declarations
3021 .map(|declarations| place_state_interner.intern_declarations(declarations));
3022 interned_ids_by_definition.push((
3023 definition,
3024 DefinitionsAtDefinition {
3025 bindings,
3026 declarations,
3027 },
3028 ));
3029 }
3030
3031 FrozenMap::from_entries(interned_ids_by_definition)
3032 }
3033
3034 fn intern_bindings_by_use(
3035 bindings_by_use: IndexVec<ScopedUseId, Bindings>,
3036 place_state_interner: &mut PlaceStateInterner,
3037 ) -> IndexVec<ScopedUseId, InternedBindingsId> {
3038 let mut interned_ids_by_use: IndexVec<ScopedUseId, InternedBindingsId> =
3039 IndexVec::with_capacity(bindings_by_use.len());
3040
3041 for bindings in bindings_by_use {
3042 let interned_id = place_state_interner.intern_bindings(&bindings);
3043 interned_ids_by_use.push(interned_id);
3044 }
3045
3046 interned_ids_by_use
3047 }
3048
3049 fn intern_place_states<I: Idx, T>(
3050 place_states: IndexVec<I, T>,
3051 get_parts: impl Fn(T) -> (Bindings, Declarations),
3052 place_state_interner: &mut PlaceStateInterner,
3053 ) -> IndexVec<I, InternedPlaceStateId> {
3054 let mut interned_ids_by_place = IndexVec::with_capacity(place_states.len());
3055
3056 for place_state in place_states {
3057 let (bindings, declarations) = get_parts(place_state);
3058 let interned_id = place_state_interner.retain_place_state(&bindings, declarations);
3059 interned_ids_by_place.push(interned_id);
3060 }
3061
3062 interned_ids_by_place
3063 }
3064
3065 fn intern_end_of_scope_members(
3066 end_of_scope_members: IndexVec<ScopedMemberId, PlaceState>,
3067 place_state_interner: &mut PlaceStateInterner,
3068 ) -> IndexVec<ScopedMemberId, InternedPlaceStateId> {
3069 let mut interned_ids_by_member = IndexVec::with_capacity(end_of_scope_members.len());
3070 let mut interned_ids_by_place_state =
3071 FxHashMap::with_capacity_and_hasher(end_of_scope_members.len(), FxBuildHasher);
3072
3073 for place_state in end_of_scope_members {
3074 let interned_id = match interned_ids_by_place_state.entry(place_state) {
3075 Entry::Occupied(entry) => *entry.get(),
3076 Entry::Vacant(entry) => {
3077 let place_state = entry.key();
3078 let interned_id = place_state_interner.intern_place_state(
3079 place_state.bindings(),
3080 place_state.declarations().clone(),
3081 );
3082 entry.insert(interned_id);
3083 interned_id
3084 }
3085 };
3086 interned_ids_by_member.push(interned_id);
3087 }
3088
3089 interned_ids_by_member
3090 }
3091
3092 fn intern_enclosing_snapshots(
3093 enclosing_snapshots: EnclosingSnapshots,
3094 place_state_interner: &mut PlaceStateInterner,
3095 ) -> IndexVec<ScopedEnclosingSnapshotId, InternedEnclosingSnapshotId> {
3096 let mut interned_ids_by_snapshot: IndexVec<
3097 ScopedEnclosingSnapshotId,
3098 InternedEnclosingSnapshotId,
3099 > = IndexVec::with_capacity(enclosing_snapshots.len());
3100
3101 for snapshot in enclosing_snapshots {
3102 let interned_id = match snapshot {
3103 EnclosingSnapshot::Bindings(bindings) => {
3104 let interned_bindings_id = place_state_interner.intern_bindings(&bindings);
3105 InternedEnclosingSnapshotId::Bindings(interned_bindings_id)
3106 }
3107 EnclosingSnapshot::Constraint(constraint) => {
3108 InternedEnclosingSnapshotId::Constraint(constraint)
3109 }
3110 };
3111 interned_ids_by_snapshot.push(interned_id);
3112 }
3113
3114 interned_ids_by_snapshot
3115 }
3116}