Introduce VisibilityConstraints struct
This commit is contained in:
@@ -27,7 +27,7 @@ pub mod definition;
|
||||
pub mod expression;
|
||||
pub mod symbol;
|
||||
mod use_def;
|
||||
pub(crate) mod visibility_constraint;
|
||||
pub(crate) mod visibility_constraints;
|
||||
|
||||
pub(crate) use self::use_def::{
|
||||
BindingWithConstraints, BindingWithConstraintsIterator, DeclarationsIterator,
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::semantic_index::symbol::{
|
||||
use crate::semantic_index::use_def::{
|
||||
FlowSnapshot, ScopedConstraintId, ScopedVisibilityConstraintId, UseDefMapBuilder,
|
||||
};
|
||||
use crate::semantic_index::visibility_constraint::VisibilityConstraintRef;
|
||||
use crate::semantic_index::visibility_constraints::VisibilityConstraintRef;
|
||||
use crate::semantic_index::SemanticIndex;
|
||||
use crate::unpack::Unpack;
|
||||
use crate::Db;
|
||||
|
||||
@@ -229,7 +229,9 @@ pub(crate) use self::symbol_state::{ScopedConstraintId, ScopedVisibilityConstrai
|
||||
use crate::semantic_index::ast_ids::ScopedUseId;
|
||||
use crate::semantic_index::definition::Definition;
|
||||
use crate::semantic_index::symbol::ScopedSymbolId;
|
||||
pub(crate) use crate::semantic_index::visibility_constraint::VisibilityConstraintRef;
|
||||
use crate::semantic_index::visibility_constraints::{
|
||||
VisibilityConstraintRef, VisibilityConstraints,
|
||||
};
|
||||
use ruff_index::IndexVec;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
@@ -248,7 +250,7 @@ pub(crate) struct UseDefMap<'db> {
|
||||
all_constraints: IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
|
||||
/// Array of [`VisibilityConstraintRef`] in this scope.
|
||||
all_visibility_constraints: IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
all_visibility_constraints: VisibilityConstraints,
|
||||
|
||||
/// [`SymbolBindings`] reaching a [`ScopedUseId`].
|
||||
bindings_by_use: IndexVec<ScopedUseId, SymbolBindings>,
|
||||
@@ -389,8 +391,7 @@ pub(crate) struct BindingWithConstraints<'map, 'db> {
|
||||
pub(crate) binding: Option<Definition<'db>>,
|
||||
pub(crate) constraints: ConstraintsIterator<'map, 'db>,
|
||||
pub(crate) all_constraints: &'map IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
pub(crate) all_visibility_constraints:
|
||||
&'map IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
pub(crate) all_visibility_constraints: &'map VisibilityConstraints,
|
||||
pub(crate) visibility_constraint: ScopedVisibilityConstraintId,
|
||||
}
|
||||
|
||||
@@ -420,7 +421,7 @@ impl<'map, 'db> Iterator for DeclarationsIterator<'map, 'db> {
|
||||
type Item = (
|
||||
Option<Definition<'db>>,
|
||||
&'map IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
&'map IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
&'map VisibilityConstraints,
|
||||
ScopedVisibilityConstraintId,
|
||||
);
|
||||
|
||||
@@ -456,7 +457,7 @@ pub(super) struct UseDefMapBuilder<'db> {
|
||||
all_constraints: IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
|
||||
/// Append-only array of [`VisibilityConstraintRef`].
|
||||
all_visibility_constraints: IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
all_visibility_constraints: VisibilityConstraints,
|
||||
|
||||
unbound_visibility_constraint_id: ScopedVisibilityConstraintId,
|
||||
|
||||
@@ -475,7 +476,7 @@ impl<'db> UseDefMapBuilder<'db> {
|
||||
Self {
|
||||
all_definitions: IndexVec::from_iter([None]),
|
||||
all_constraints: IndexVec::new(),
|
||||
all_visibility_constraints: IndexVec::from_iter([VisibilityConstraintRef::None]),
|
||||
all_visibility_constraints: VisibilityConstraints::new(),
|
||||
unbound_visibility_constraint_id: ScopedVisibilityConstraintId::from_u32(0),
|
||||
bindings_by_use: IndexVec::new(),
|
||||
definitions_by_definition: FxHashMap::default(),
|
||||
@@ -512,7 +513,7 @@ impl<'db> UseDefMapBuilder<'db> {
|
||||
&mut self,
|
||||
constraint: VisibilityConstraintRef,
|
||||
) -> ScopedVisibilityConstraintId {
|
||||
self.all_visibility_constraints.push(constraint)
|
||||
self.all_visibility_constraints.add(constraint)
|
||||
}
|
||||
|
||||
pub(super) fn record_visibility_constraint(
|
||||
@@ -532,7 +533,7 @@ impl<'db> UseDefMapBuilder<'db> {
|
||||
} else {
|
||||
self.unbound_visibility_constraint_id =
|
||||
self.all_visibility_constraints
|
||||
.push(VisibilityConstraintRef::Sequence(
|
||||
.add(VisibilityConstraintRef::Sequence(
|
||||
self.unbound_visibility_constraint_id,
|
||||
new_constraint_id,
|
||||
));
|
||||
@@ -644,31 +645,11 @@ impl<'db> UseDefMapBuilder<'db> {
|
||||
}
|
||||
|
||||
// Merge unbound visibility constraints:
|
||||
match (
|
||||
&self.all_visibility_constraints[self.unbound_visibility_constraint_id],
|
||||
&self.all_visibility_constraints[snapshot.unbound_visibility_constraint_id],
|
||||
) {
|
||||
(_, VisibilityConstraintRef::Negated(id))
|
||||
if self.unbound_visibility_constraint_id == *id =>
|
||||
{
|
||||
self.unbound_visibility_constraint_id = ScopedVisibilityConstraintId::from_u32(0);
|
||||
}
|
||||
|
||||
(VisibilityConstraintRef::Negated(id), _)
|
||||
if *id == snapshot.unbound_visibility_constraint_id =>
|
||||
{
|
||||
self.unbound_visibility_constraint_id = ScopedVisibilityConstraintId::from_u32(0);
|
||||
}
|
||||
_ => {
|
||||
let constraint_id =
|
||||
self.all_visibility_constraints
|
||||
.push(VisibilityConstraintRef::Merged(
|
||||
self.unbound_visibility_constraint_id,
|
||||
snapshot.unbound_visibility_constraint_id,
|
||||
));
|
||||
self.unbound_visibility_constraint_id = constraint_id;
|
||||
}
|
||||
}
|
||||
self.unbound_visibility_constraint_id = self.all_visibility_constraints.add_merged(
|
||||
self.unbound_visibility_constraint_id,
|
||||
snapshot.unbound_visibility_constraint_id,
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn finish(mut self) -> UseDefMap<'db> {
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
//!
|
||||
//! Tracking live declarations is simpler, since constraints are not involved, but otherwise very
|
||||
//! similar to tracking live bindings.
|
||||
use crate::semantic_index::use_def::{Constraint, VisibilityConstraintRef};
|
||||
use crate::semantic_index::use_def::{Constraint, VisibilityConstraintRef, VisibilityConstraints};
|
||||
|
||||
use super::bitset::{BitSet, BitSetIterator};
|
||||
use ruff_index::{newtype_index, IndexVec};
|
||||
@@ -131,10 +131,7 @@ impl SymbolDeclarations {
|
||||
/// Add given visibility constraint to all live bindings.
|
||||
pub(super) fn record_visibility_constraint(
|
||||
&mut self,
|
||||
all_visibility_constraints: &mut IndexVec<
|
||||
ScopedVisibilityConstraintId,
|
||||
VisibilityConstraintRef,
|
||||
>,
|
||||
all_visibility_constraints: &mut VisibilityConstraints,
|
||||
constraint: ScopedVisibilityConstraintId,
|
||||
) {
|
||||
for existing in &mut self.visibility_constraints {
|
||||
@@ -142,7 +139,7 @@ impl SymbolDeclarations {
|
||||
*existing = constraint;
|
||||
} else {
|
||||
*existing = all_visibility_constraints
|
||||
.push(VisibilityConstraintRef::Sequence(*existing, constraint));
|
||||
.add(VisibilityConstraintRef::Sequence(*existing, constraint));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -214,10 +211,7 @@ impl SymbolBindings {
|
||||
/// Add given visibility constraint to all live bindings.
|
||||
pub(super) fn record_visibility_constraint(
|
||||
&mut self,
|
||||
all_visibility_constraints: &mut IndexVec<
|
||||
ScopedVisibilityConstraintId,
|
||||
VisibilityConstraintRef,
|
||||
>,
|
||||
all_visibility_constraints: &mut VisibilityConstraints,
|
||||
constraint: ScopedVisibilityConstraintId,
|
||||
) {
|
||||
for existing in &mut self.visibility_constraints {
|
||||
@@ -225,7 +219,7 @@ impl SymbolBindings {
|
||||
*existing = constraint;
|
||||
} else {
|
||||
*existing = all_visibility_constraints
|
||||
.push(VisibilityConstraintRef::Sequence(*existing, constraint));
|
||||
.add(VisibilityConstraintRef::Sequence(*existing, constraint));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,10 +228,7 @@ impl SymbolBindings {
|
||||
pub(super) fn iter<'map, 'db>(
|
||||
&'map self,
|
||||
all_constraints: &'map IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
all_visibility_constraints: &'map IndexVec<
|
||||
ScopedVisibilityConstraintId,
|
||||
VisibilityConstraintRef,
|
||||
>,
|
||||
all_visibility_constraints: &'map VisibilityConstraints,
|
||||
) -> BindingIdWithConstraintsIterator<'map, 'db> {
|
||||
BindingIdWithConstraintsIterator {
|
||||
all_constraints,
|
||||
@@ -277,10 +268,7 @@ impl SymbolState {
|
||||
/// Add given visibility constraint to all live bindings.
|
||||
pub(super) fn record_visibility_constraint(
|
||||
&mut self,
|
||||
all_visibility_constraints: &mut IndexVec<
|
||||
ScopedVisibilityConstraintId,
|
||||
VisibilityConstraintRef,
|
||||
>,
|
||||
all_visibility_constraints: &mut VisibilityConstraints,
|
||||
constraint: ScopedVisibilityConstraintId,
|
||||
) {
|
||||
self.bindings
|
||||
@@ -308,10 +296,7 @@ impl SymbolState {
|
||||
pub(super) fn merge(
|
||||
&mut self,
|
||||
b: SymbolState,
|
||||
all_visibility_constraints: &mut IndexVec<
|
||||
ScopedVisibilityConstraintId,
|
||||
VisibilityConstraintRef,
|
||||
>,
|
||||
all_visibility_constraints: &mut VisibilityConstraints,
|
||||
) {
|
||||
let mut a = Self {
|
||||
bindings: SymbolBindings {
|
||||
@@ -422,26 +407,8 @@ impl SymbolState {
|
||||
.next()
|
||||
.expect("visibility_constraints length mismatch");
|
||||
let current = self.bindings.visibility_constraints.last_mut().unwrap();
|
||||
match (
|
||||
&all_visibility_constraints[*current],
|
||||
&all_visibility_constraints[a_vis_constraint],
|
||||
) {
|
||||
(_, VisibilityConstraintRef::Negated(id)) if current == id => {
|
||||
*current = ScopedVisibilityConstraintId::from_u32(0);
|
||||
}
|
||||
|
||||
(VisibilityConstraintRef::Negated(id), _)
|
||||
if *id == a_vis_constraint =>
|
||||
{
|
||||
*current = ScopedVisibilityConstraintId::from_u32(0);
|
||||
}
|
||||
_ => {
|
||||
let constraint_id = all_visibility_constraints.push(
|
||||
VisibilityConstraintRef::Merged(*current, a_vis_constraint),
|
||||
);
|
||||
*current = constraint_id;
|
||||
}
|
||||
}
|
||||
*current =
|
||||
all_visibility_constraints.add_merged(*current, a_vis_constraint);
|
||||
|
||||
opt_a_def = a_defs_iter.next();
|
||||
opt_b_def = b_defs_iter.next();
|
||||
@@ -507,26 +474,8 @@ impl SymbolState {
|
||||
.next()
|
||||
.expect("declarations and visibility_constraints length mismatch");
|
||||
let current = self.declarations.visibility_constraints.last_mut().unwrap();
|
||||
match (
|
||||
&all_visibility_constraints[*current],
|
||||
&all_visibility_constraints[a_vis_constraint],
|
||||
) {
|
||||
(_, VisibilityConstraintRef::Negated(id)) if current == id => {
|
||||
*current = ScopedVisibilityConstraintId::from_u32(0);
|
||||
}
|
||||
|
||||
(VisibilityConstraintRef::Negated(id), _)
|
||||
if *id == a_vis_constraint =>
|
||||
{
|
||||
*current = ScopedVisibilityConstraintId::from_u32(0);
|
||||
}
|
||||
_ => {
|
||||
let constraint_id = all_visibility_constraints.push(
|
||||
VisibilityConstraintRef::Merged(*current, a_vis_constraint),
|
||||
);
|
||||
*current = constraint_id;
|
||||
}
|
||||
}
|
||||
*current =
|
||||
all_visibility_constraints.add_merged(*current, a_vis_constraint);
|
||||
|
||||
opt_a_decl = a_decls_iter.next();
|
||||
opt_b_decl = b_decls_iter.next();
|
||||
@@ -561,16 +510,14 @@ pub(super) struct BindingIdWithConstraints<'map, 'db> {
|
||||
pub(super) definition: ScopedDefinitionId,
|
||||
pub(super) constraint_ids: ConstraintIdIterator<'map>,
|
||||
pub(super) all_constraints: &'map IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
pub(super) all_visibility_constraints:
|
||||
&'map IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
pub(super) all_visibility_constraints: &'map VisibilityConstraints,
|
||||
pub(super) visibility_constraint: ScopedVisibilityConstraintId,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct BindingIdWithConstraintsIterator<'map, 'db> {
|
||||
all_constraints: &'map IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
all_visibility_constraints:
|
||||
&'map IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
all_visibility_constraints: &'map VisibilityConstraints,
|
||||
definitions: BindingsIterator<'map>,
|
||||
constraints: ConstraintsIterator<'map>,
|
||||
visibility_constraints: VisibilityConstraintsIterator<'map>,
|
||||
@@ -622,8 +569,7 @@ impl std::iter::FusedIterator for ConstraintIdIterator<'_> {}
|
||||
|
||||
pub(super) struct DeclarationIdIterator<'map, 'db> {
|
||||
pub(crate) all_constraints: &'map IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
pub(crate) all_visibility_constraints:
|
||||
&'map IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
pub(crate) all_visibility_constraints: &'map VisibilityConstraints,
|
||||
pub(crate) inner: DeclarationsIterator<'map>,
|
||||
pub(crate) visibility_constraints: VisibilityConstraintsIterator<'map>,
|
||||
}
|
||||
@@ -632,7 +578,7 @@ impl<'map, 'db> Iterator for DeclarationIdIterator<'map, 'db> {
|
||||
type Item = (
|
||||
ScopedDefinitionId,
|
||||
&'map IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
&'map IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
&'map VisibilityConstraints,
|
||||
ScopedVisibilityConstraintId,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
use crate::semantic_index::use_def::{ScopedConstraintId, ScopedVisibilityConstraintId};
|
||||
|
||||
/// TODO
|
||||
///
|
||||
/// Used to represent active branching conditions that apply to a particular definition.
|
||||
/// A definition can either be conditional on a specific constraint from a `if`, `elif`,
|
||||
/// `while` statement, an `if`-expression, or a Boolean expression. Or it can be marked
|
||||
/// as 'ambiguous' if it occurred in a control-flow path that is not conditional on any
|
||||
/// specific expression that can be statically analyzed (`for` loop, `try` ... `except`).
|
||||
///
|
||||
///
|
||||
/// For example:
|
||||
/// ```py
|
||||
/// a = 1 # no visibility constraints
|
||||
///
|
||||
/// if test1:
|
||||
/// b = 1 # Constraint(test1)
|
||||
///
|
||||
/// if test2:
|
||||
/// c = 1 # Constraint(test1), Constraint(test2)
|
||||
///
|
||||
/// for _ in range(10):
|
||||
/// d = 1 # Constraint(test1), Ambiguous
|
||||
/// else:
|
||||
/// d = 1 # Constraint(~test1)
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum VisibilityConstraintRef {
|
||||
None,
|
||||
Single(ScopedConstraintId),
|
||||
Negated(ScopedVisibilityConstraintId),
|
||||
Sequence(ScopedVisibilityConstraintId, ScopedVisibilityConstraintId),
|
||||
Merged(ScopedVisibilityConstraintId, ScopedVisibilityConstraintId),
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
use std::ops::Index;
|
||||
|
||||
use ruff_index::IndexVec;
|
||||
|
||||
use crate::semantic_index::{ScopedConstraintId, ScopedVisibilityConstraintId};
|
||||
|
||||
/// TODO
|
||||
///
|
||||
/// Used to represent active branching conditions that apply to a particular definition.
|
||||
/// A definition can either be conditional on a specific constraint from a `if`, `elif`,
|
||||
/// `while` statement, an `if`-expression, or a Boolean expression. Or it can be marked
|
||||
/// as 'ambiguous' if it occurred in a control-flow path that is not conditional on any
|
||||
/// specific expression that can be statically analyzed (`for` loop, `try` ... `except`).
|
||||
///
|
||||
///
|
||||
/// For example:
|
||||
/// ```py
|
||||
/// a = 1 # no visibility constraints
|
||||
///
|
||||
/// if test1:
|
||||
/// b = 1 # Constraint(test1)
|
||||
///
|
||||
/// if test2:
|
||||
/// c = 1 # Constraint(test1), Constraint(test2)
|
||||
///
|
||||
/// for _ in range(10):
|
||||
/// d = 1 # Constraint(test1), Ambiguous
|
||||
/// else:
|
||||
/// d = 1 # Constraint(~test1)
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum VisibilityConstraintRef {
|
||||
None,
|
||||
Single(ScopedConstraintId),
|
||||
Negated(ScopedVisibilityConstraintId),
|
||||
Sequence(ScopedVisibilityConstraintId, ScopedVisibilityConstraintId),
|
||||
Merged(ScopedVisibilityConstraintId, ScopedVisibilityConstraintId),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub(crate) struct VisibilityConstraints {
|
||||
constraints: IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
}
|
||||
|
||||
impl VisibilityConstraints {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
constraints: IndexVec::from_iter([VisibilityConstraintRef::None]),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add(
|
||||
&mut self,
|
||||
constraint: VisibilityConstraintRef,
|
||||
) -> ScopedVisibilityConstraintId {
|
||||
self.constraints.push(constraint)
|
||||
}
|
||||
|
||||
pub(crate) fn add_merged(
|
||||
&mut self,
|
||||
a: ScopedVisibilityConstraintId,
|
||||
b: ScopedVisibilityConstraintId,
|
||||
) -> ScopedVisibilityConstraintId {
|
||||
match (&self.constraints[a], &self.constraints[b]) {
|
||||
(_, VisibilityConstraintRef::Negated(id)) if a == *id => {
|
||||
ScopedVisibilityConstraintId::from_u32(0)
|
||||
}
|
||||
(VisibilityConstraintRef::Negated(id), _) if *id == b => {
|
||||
ScopedVisibilityConstraintId::from_u32(0)
|
||||
}
|
||||
_ => self.add(VisibilityConstraintRef::Merged(a, b)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<ScopedVisibilityConstraintId> for VisibilityConstraints {
|
||||
type Output = VisibilityConstraintRef;
|
||||
|
||||
fn index(&self, index: ScopedVisibilityConstraintId) -> &Self::Output {
|
||||
&self.constraints[index]
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,8 @@ use ruff_index::IndexVec;
|
||||
use crate::semantic_index::{
|
||||
ast_ids::HasScopedExpressionId,
|
||||
constraint::{Constraint, ConstraintNode, PatternConstraintKind},
|
||||
visibility_constraint::VisibilityConstraintRef,
|
||||
visibility_constraints::VisibilityConstraintRef,
|
||||
visibility_constraints::VisibilityConstraints,
|
||||
ScopedConstraintId, ScopedVisibilityConstraintId,
|
||||
};
|
||||
use crate::types::{infer_expression_types, Truthiness};
|
||||
@@ -15,7 +16,7 @@ const MAX_RECURSION_DEPTH: usize = 10;
|
||||
pub(crate) fn analyze<'db>(
|
||||
db: &'db dyn Db,
|
||||
all_constraints: &IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
all_visibility_constraints: &IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
all_visibility_constraints: &VisibilityConstraints,
|
||||
visibility_constraint_id: ScopedVisibilityConstraintId,
|
||||
) -> Truthiness {
|
||||
analyze_impl(
|
||||
@@ -30,7 +31,7 @@ pub(crate) fn analyze<'db>(
|
||||
fn analyze_impl<'db>(
|
||||
db: &'db dyn Db,
|
||||
all_constraints: &IndexVec<ScopedConstraintId, Constraint<'db>>,
|
||||
all_visibility_constraints: &IndexVec<ScopedVisibilityConstraintId, VisibilityConstraintRef>,
|
||||
all_visibility_constraints: &VisibilityConstraints,
|
||||
visibility_constraint_id: ScopedVisibilityConstraintId,
|
||||
max_depth: usize,
|
||||
) -> Truthiness {
|
||||
|
||||
Reference in New Issue
Block a user