Compare commits

...

1 Commits

Author SHA1 Message Date
Dhruv Manilawala
d3db7cb04d Avoid declarations in exception control flow 2024-12-13 18:17:50 +05:30
3 changed files with 30 additions and 18 deletions

View File

@@ -205,7 +205,11 @@ impl<'db> SemanticIndexBuilder<'db> {
} }
fn flow_merge(&mut self, state: FlowSnapshot) { fn flow_merge(&mut self, state: FlowSnapshot) {
self.current_use_def_map_mut().merge(state); self.current_use_def_map_mut().merge(state, false);
}
fn flow_merge_no_declarations(&mut self, state: FlowSnapshot) {
self.current_use_def_map_mut().merge(state, true);
} }
fn add_symbol(&mut self, name: Name) -> ScopedSymbolId { fn add_symbol(&mut self, name: Name) -> ScopedSymbolId {
@@ -1002,7 +1006,7 @@ where
// Prepare for visiting the `except` block(s) // Prepare for visiting the `except` block(s)
self.flow_restore(pre_try_block_state); self.flow_restore(pre_try_block_state);
for state in try_block_snapshots { for state in try_block_snapshots {
self.flow_merge(state); self.flow_merge_no_declarations(state);
} }
let pre_except_state = self.flow_snapshot(); let pre_except_state = self.flow_snapshot();

View File

@@ -544,7 +544,7 @@ impl<'db> UseDefMapBuilder<'db> {
/// Merge the given snapshot into the current state, reflecting that we might have taken either /// Merge the given snapshot into the current state, reflecting that we might have taken either
/// path to get here. The new state for each symbol should include definitions from both the /// path to get here. The new state for each symbol should include definitions from both the
/// prior state and the snapshot. /// prior state and the snapshot.
pub(super) fn merge(&mut self, snapshot: FlowSnapshot) { pub(super) fn merge(&mut self, snapshot: FlowSnapshot, exclude_declarations: bool) {
// We never remove symbols from `symbol_states` (it's an IndexVec, and the symbol // We never remove symbols from `symbol_states` (it's an IndexVec, and the symbol
// IDs must line up), so the current number of known symbols must always be equal to or // IDs must line up), so the current number of known symbols must always be equal to or
// greater than the number of known symbols in a previously-taken snapshot. // greater than the number of known symbols in a previously-taken snapshot.
@@ -553,7 +553,7 @@ impl<'db> UseDefMapBuilder<'db> {
let mut snapshot_definitions_iter = snapshot.symbol_states.into_iter(); let mut snapshot_definitions_iter = snapshot.symbol_states.into_iter();
for current in &mut self.symbol_states { for current in &mut self.symbol_states {
if let Some(snapshot) = snapshot_definitions_iter.next() { if let Some(snapshot) = snapshot_definitions_iter.next() {
current.merge(snapshot); current.merge(snapshot, exclude_declarations);
} else { } else {
// Symbol not present in snapshot, so it's unbound/undeclared from that path. // Symbol not present in snapshot, so it's unbound/undeclared from that path.
current.set_may_be_unbound(); current.set_may_be_unbound();

View File

@@ -227,24 +227,32 @@ impl SymbolState {
} }
/// Merge another [`SymbolState`] into this one. /// Merge another [`SymbolState`] into this one.
pub(super) fn merge(&mut self, b: SymbolState) { pub(super) fn merge(&mut self, b: SymbolState, exclude_declarations: bool) {
let mut a = Self { let mut a = Self {
bindings: SymbolBindings { bindings: SymbolBindings {
live_bindings: Bindings::default(), live_bindings: Bindings::default(),
constraints: Constraints::default(), constraints: Constraints::default(),
may_be_unbound: self.bindings.may_be_unbound || b.bindings.may_be_unbound, may_be_unbound: self.bindings.may_be_unbound || b.bindings.may_be_unbound,
}, },
declarations: SymbolDeclarations { declarations: {
live_declarations: self.declarations.live_declarations.clone(), if exclude_declarations {
may_be_undeclared: self.declarations.may_be_undeclared self.declarations.clone()
|| b.declarations.may_be_undeclared, } else {
SymbolDeclarations {
live_declarations: self.declarations.live_declarations.clone(),
may_be_undeclared: self.declarations.may_be_undeclared
|| b.declarations.may_be_undeclared,
}
}
}, },
}; };
std::mem::swap(&mut a, self); std::mem::swap(&mut a, self);
self.declarations if !exclude_declarations {
.live_declarations self.declarations
.union(&b.declarations.live_declarations); .live_declarations
.union(&b.declarations.live_declarations);
}
let mut a_defs_iter = a.bindings.live_bindings.iter(); let mut a_defs_iter = a.bindings.live_bindings.iter();
let mut b_defs_iter = b.bindings.live_bindings.iter(); let mut b_defs_iter = b.bindings.live_bindings.iter();
@@ -494,7 +502,7 @@ mod tests {
sym0b.record_binding(ScopedDefinitionId::from_u32(0)); sym0b.record_binding(ScopedDefinitionId::from_u32(0));
sym0b.record_constraint(ScopedConstraintId::from_u32(0)); sym0b.record_constraint(ScopedConstraintId::from_u32(0));
sym0a.merge(sym0b); sym0a.merge(sym0b, false);
let mut sym0 = sym0a; let mut sym0 = sym0a;
assert_bindings(&sym0, false, &["0<0>"]); assert_bindings(&sym0, false, &["0<0>"]);
@@ -507,7 +515,7 @@ mod tests {
sym1b.record_binding(ScopedDefinitionId::from_u32(1)); sym1b.record_binding(ScopedDefinitionId::from_u32(1));
sym1b.record_constraint(ScopedConstraintId::from_u32(2)); sym1b.record_constraint(ScopedConstraintId::from_u32(2));
sym1a.merge(sym1b); sym1a.merge(sym1b, false);
let sym1 = sym1a; let sym1 = sym1a;
assert_bindings(&sym1, false, &["1<>"]); assert_bindings(&sym1, false, &["1<>"]);
@@ -518,12 +526,12 @@ mod tests {
let sym2b = SymbolState::undefined(); let sym2b = SymbolState::undefined();
sym2a.merge(sym2b); sym2a.merge(sym2b, false);
let sym2 = sym2a; let sym2 = sym2a;
assert_bindings(&sym2, true, &["2<3>"]); assert_bindings(&sym2, true, &["2<3>"]);
// merging different definitions keeps them each with their existing constraints // merging different definitions keeps them each with their existing constraints
sym0.merge(sym2); sym0.merge(sym2, false);
let sym = sym0; let sym = sym0;
assert_bindings(&sym, true, &["0<0>", "2<3>"]); assert_bindings(&sym, true, &["0<0>", "2<3>"]);
} }
@@ -560,7 +568,7 @@ mod tests {
let mut sym2 = SymbolState::undefined(); let mut sym2 = SymbolState::undefined();
sym2.record_declaration(ScopedDefinitionId::from_u32(2)); sym2.record_declaration(ScopedDefinitionId::from_u32(2));
sym.merge(sym2); sym.merge(sym2, false);
assert_declarations(&sym, false, &[1, 2]); assert_declarations(&sym, false, &[1, 2]);
} }
@@ -572,7 +580,7 @@ mod tests {
let sym2 = SymbolState::undefined(); let sym2 = SymbolState::undefined();
sym.merge(sym2); sym.merge(sym2, false);
assert_declarations(&sym, true, &[1]); assert_declarations(&sym, true, &[1]);
} }