Compare commits
9 Commits
dcreager/s
...
dcreager/i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5befdf8ff | ||
|
|
a5f5aa4a6b | ||
|
|
3dfcf91a1e | ||
|
|
0adea712ef | ||
|
|
ca5a6eef69 | ||
|
|
c2060f601f | ||
|
|
8abc134582 | ||
|
|
6f5ff25876 | ||
|
|
35578672a4 |
@@ -1,4 +1,3 @@
|
||||
use std::iter::FusedIterator;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
@@ -6,7 +5,7 @@ use salsa::plumbing::AsId;
|
||||
|
||||
use ruff_db::files::File;
|
||||
use ruff_db::parsed::parsed_module;
|
||||
use ruff_index::{IndexSlice, IndexVec};
|
||||
use ruff_index::IndexVec;
|
||||
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
|
||||
@@ -17,7 +16,6 @@ use crate::semantic_index::expression::Expression;
|
||||
use crate::semantic_index::symbol::{
|
||||
FileScopeId, NodeWithScopeKey, NodeWithScopeRef, Scope, ScopeId, ScopedSymbolId, SymbolTable,
|
||||
};
|
||||
use crate::semantic_index::use_def::UseDefMap;
|
||||
use crate::Db;
|
||||
|
||||
pub mod ast_ids;
|
||||
@@ -29,8 +27,7 @@ pub mod symbol;
|
||||
mod use_def;
|
||||
|
||||
pub(crate) use self::use_def::{
|
||||
BindingWithConstraints, BindingWithConstraintsIterator, DeclarationWithConstraint,
|
||||
DeclarationsIterator, ScopedVisibilityConstraintId,
|
||||
BindingWithConstraints, DeclarationWithConstraint, ScopedVisibilityConstraintId, UseDefMap,
|
||||
};
|
||||
|
||||
type SymbolMap = hashbrown::HashMap<ScopedSymbolId, (), FxBuildHasher>;
|
||||
@@ -206,20 +203,43 @@ impl<'db> SemanticIndex<'db> {
|
||||
|
||||
/// Returns an iterator over the descendent scopes of `scope`.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn descendent_scopes(&self, scope: FileScopeId) -> DescendentsIter {
|
||||
DescendentsIter::new(self, scope)
|
||||
pub(crate) fn descendent_scopes(
|
||||
&self,
|
||||
scope_id: FileScopeId,
|
||||
) -> impl Iterator<Item = (FileScopeId, &Scope)> + '_ {
|
||||
let scope = &self.scopes[scope_id];
|
||||
let scopes = &self.scopes[scope.descendents.clone()];
|
||||
let mut next_id = scope_id + 1;
|
||||
scopes.iter().map(move |descendent| {
|
||||
let result = (next_id, descendent);
|
||||
next_id = next_id + 1;
|
||||
result
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator over the direct child scopes of `scope`.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn child_scopes(&self, scope: FileScopeId) -> ChildrenIter {
|
||||
ChildrenIter::new(self, scope)
|
||||
pub(crate) fn child_scopes(
|
||||
&self,
|
||||
scope_id: FileScopeId,
|
||||
) -> impl Iterator<Item = (FileScopeId, &Scope)> + '_ {
|
||||
self.descendent_scopes(scope_id)
|
||||
.filter(move |(_, scope)| scope.parent == Some(scope_id))
|
||||
}
|
||||
|
||||
/// Returns an iterator over all ancestors of `scope`, starting with `scope` itself.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn ancestor_scopes(&self, scope: FileScopeId) -> AncestorsIter {
|
||||
AncestorsIter::new(self, scope)
|
||||
pub(crate) fn ancestor_scopes(
|
||||
&self,
|
||||
scope_id: FileScopeId,
|
||||
) -> impl Iterator<Item = (FileScopeId, &Scope)> + '_ {
|
||||
let mut next_id = Some(scope_id);
|
||||
std::iter::from_fn(move || {
|
||||
let current_id = next_id?;
|
||||
let current = &self.scopes[current_id];
|
||||
next_id = current.parent;
|
||||
Some((current_id, current))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the [`Definition`] salsa ingredient for `definition_key`.
|
||||
@@ -266,98 +286,6 @@ impl<'db> SemanticIndex<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AncestorsIter<'a> {
|
||||
scopes: &'a IndexSlice<FileScopeId, Scope>,
|
||||
next_id: Option<FileScopeId>,
|
||||
}
|
||||
|
||||
impl<'a> AncestorsIter<'a> {
|
||||
fn new(module_symbol_table: &'a SemanticIndex, start: FileScopeId) -> Self {
|
||||
Self {
|
||||
scopes: &module_symbol_table.scopes,
|
||||
next_id: Some(start),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for AncestorsIter<'a> {
|
||||
type Item = (FileScopeId, &'a Scope);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let current_id = self.next_id?;
|
||||
let current = &self.scopes[current_id];
|
||||
self.next_id = current.parent;
|
||||
|
||||
Some((current_id, current))
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedIterator for AncestorsIter<'_> {}
|
||||
|
||||
pub struct DescendentsIter<'a> {
|
||||
next_id: FileScopeId,
|
||||
descendents: std::slice::Iter<'a, Scope>,
|
||||
}
|
||||
|
||||
impl<'a> DescendentsIter<'a> {
|
||||
fn new(symbol_table: &'a SemanticIndex, scope_id: FileScopeId) -> Self {
|
||||
let scope = &symbol_table.scopes[scope_id];
|
||||
let scopes = &symbol_table.scopes[scope.descendents.clone()];
|
||||
|
||||
Self {
|
||||
next_id: scope_id + 1,
|
||||
descendents: scopes.iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for DescendentsIter<'a> {
|
||||
type Item = (FileScopeId, &'a Scope);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let descendent = self.descendents.next()?;
|
||||
let id = self.next_id;
|
||||
self.next_id = self.next_id + 1;
|
||||
|
||||
Some((id, descendent))
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.descendents.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedIterator for DescendentsIter<'_> {}
|
||||
|
||||
impl ExactSizeIterator for DescendentsIter<'_> {}
|
||||
|
||||
pub struct ChildrenIter<'a> {
|
||||
parent: FileScopeId,
|
||||
descendents: DescendentsIter<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ChildrenIter<'a> {
|
||||
fn new(module_symbol_table: &'a SemanticIndex, parent: FileScopeId) -> Self {
|
||||
let descendents = DescendentsIter::new(module_symbol_table, parent);
|
||||
|
||||
Self {
|
||||
parent,
|
||||
descendents,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ChildrenIter<'a> {
|
||||
type Item = (FileScopeId, &'a Scope);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.descendents
|
||||
.find(|(_, scope)| scope.parent == Some(self.parent))
|
||||
}
|
||||
}
|
||||
|
||||
impl FusedIterator for ChildrenIter<'_> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ruff_db::files::{system_path_to_file, File};
|
||||
|
||||
@@ -255,11 +255,8 @@
|
||||
//! snapshot, and merging a snapshot into the current state. The logic using these methods lives in
|
||||
//! [`SemanticIndexBuilder`](crate::semantic_index::builder::SemanticIndexBuilder), e.g. where it
|
||||
//! visits a `StmtIf` node.
|
||||
use self::symbol_state::{
|
||||
BindingIdWithConstraintsIterator, ConstraintIdIterator, DeclarationIdIterator,
|
||||
ScopedDefinitionId, SymbolBindings, SymbolDeclarations, SymbolState,
|
||||
};
|
||||
pub(crate) use self::symbol_state::{ScopedConstraintId, ScopedVisibilityConstraintId};
|
||||
use self::symbol_state::{ScopedDefinitionId, SymbolBindings, SymbolDeclarations, SymbolState};
|
||||
use crate::semantic_index::ast_ids::ScopedUseId;
|
||||
use crate::semantic_index::definition::Definition;
|
||||
use crate::semantic_index::symbol::ScopedSymbolId;
|
||||
@@ -286,7 +283,7 @@ pub(crate) struct UseDefMap<'db> {
|
||||
all_constraints: AllConstraints<'db>,
|
||||
|
||||
/// Array of [`VisibilityConstraint`]s in this scope.
|
||||
visibility_constraints: VisibilityConstraints<'db>,
|
||||
pub(crate) visibility_constraints: VisibilityConstraints<'db>,
|
||||
|
||||
/// [`SymbolBindings`] reaching a [`ScopedUseId`].
|
||||
bindings_by_use: IndexVec<ScopedUseId, SymbolBindings>,
|
||||
@@ -313,21 +310,24 @@ impl<'db> UseDefMap<'db> {
|
||||
pub(crate) fn bindings_at_use(
|
||||
&self,
|
||||
use_id: ScopedUseId,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
) -> impl Iterator<Item = BindingWithConstraints<'db, impl Iterator<Item = Constraint<'db>> + '_>> + '_
|
||||
{
|
||||
self.bindings_iterator(&self.bindings_by_use[use_id])
|
||||
}
|
||||
|
||||
pub(crate) fn public_bindings(
|
||||
&self,
|
||||
symbol: ScopedSymbolId,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
) -> impl Iterator<Item = BindingWithConstraints<'db, impl Iterator<Item = Constraint<'db>> + '_>> + '_
|
||||
{
|
||||
self.bindings_iterator(self.public_symbols[symbol].bindings())
|
||||
}
|
||||
|
||||
pub(crate) fn bindings_at_declaration(
|
||||
&self,
|
||||
declaration: Definition<'db>,
|
||||
) -> BindingWithConstraintsIterator<'_, 'db> {
|
||||
) -> impl Iterator<Item = BindingWithConstraints<'db, impl Iterator<Item = Constraint<'db>> + '_>> + '_
|
||||
{
|
||||
if let SymbolDefinitions::Bindings(bindings) = &self.definitions_by_definition[&declaration]
|
||||
{
|
||||
self.bindings_iterator(bindings)
|
||||
@@ -336,10 +336,10 @@ impl<'db> UseDefMap<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn declarations_at_binding<'map>(
|
||||
&'map self,
|
||||
pub(crate) fn declarations_at_binding(
|
||||
&self,
|
||||
binding: Definition<'db>,
|
||||
) -> DeclarationsIterator<'map, 'db> {
|
||||
) -> impl Iterator<Item = DeclarationWithConstraint<'db>> + '_ {
|
||||
if let SymbolDefinitions::Declarations(declarations) =
|
||||
&self.definitions_by_definition[&binding]
|
||||
{
|
||||
@@ -349,10 +349,10 @@ impl<'db> UseDefMap<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn public_declarations<'map>(
|
||||
&'map self,
|
||||
pub(crate) fn public_declarations(
|
||||
&self,
|
||||
symbol: ScopedSymbolId,
|
||||
) -> DeclarationsIterator<'map, 'db> {
|
||||
) -> impl Iterator<Item = DeclarationWithConstraint<'db>> + '_ {
|
||||
let declarations = self.public_symbols[symbol].declarations();
|
||||
self.declarations_iterator(declarations)
|
||||
}
|
||||
@@ -360,24 +360,35 @@ impl<'db> UseDefMap<'db> {
|
||||
fn bindings_iterator<'map>(
|
||||
&'map self,
|
||||
bindings: &'map SymbolBindings,
|
||||
) -> BindingWithConstraintsIterator<'map, 'db> {
|
||||
BindingWithConstraintsIterator {
|
||||
all_definitions: &self.all_definitions,
|
||||
all_constraints: &self.all_constraints,
|
||||
visibility_constraints: &self.visibility_constraints,
|
||||
inner: bindings.iter(),
|
||||
}
|
||||
) -> impl Iterator<
|
||||
Item = BindingWithConstraints<'db, impl Iterator<Item = Constraint<'db>> + 'map>,
|
||||
> + 'map {
|
||||
bindings
|
||||
.iter()
|
||||
.map(|binding_id_with_constraints| BindingWithConstraints {
|
||||
binding: self.all_definitions[binding_id_with_constraints.definition],
|
||||
constraints: binding_id_with_constraints
|
||||
.constraint_ids
|
||||
.map(|constraint_id| self.all_constraints[constraint_id]),
|
||||
visibility_constraint: binding_id_with_constraints.visibility_constraint,
|
||||
})
|
||||
}
|
||||
|
||||
fn declarations_iterator<'map>(
|
||||
&'map self,
|
||||
declarations: &'map SymbolDeclarations,
|
||||
) -> DeclarationsIterator<'map, 'db> {
|
||||
DeclarationsIterator {
|
||||
all_definitions: &self.all_definitions,
|
||||
visibility_constraints: &self.visibility_constraints,
|
||||
inner: declarations.iter(),
|
||||
}
|
||||
) -> impl Iterator<Item = DeclarationWithConstraint<'db>> + 'map {
|
||||
declarations.iter().map(
|
||||
move |DeclarationIdWithConstraint {
|
||||
definition,
|
||||
visibility_constraint,
|
||||
}| {
|
||||
DeclarationWithConstraint {
|
||||
declaration: self.all_definitions[definition],
|
||||
visibility_constraint,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,89 +399,17 @@ enum SymbolDefinitions {
|
||||
Declarations(SymbolDeclarations),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct BindingWithConstraintsIterator<'map, 'db> {
|
||||
all_definitions: &'map IndexVec<ScopedDefinitionId, Option<Definition<'db>>>,
|
||||
all_constraints: &'map AllConstraints<'db>,
|
||||
pub(crate) visibility_constraints: &'map VisibilityConstraints<'db>,
|
||||
inner: BindingIdWithConstraintsIterator<'map>,
|
||||
}
|
||||
|
||||
impl<'map, 'db> Iterator for BindingWithConstraintsIterator<'map, 'db> {
|
||||
type Item = BindingWithConstraints<'map, 'db>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let all_constraints = self.all_constraints;
|
||||
|
||||
self.inner
|
||||
.next()
|
||||
.map(|binding_id_with_constraints| BindingWithConstraints {
|
||||
binding: self.all_definitions[binding_id_with_constraints.definition],
|
||||
constraints: ConstraintsIterator {
|
||||
all_constraints,
|
||||
constraint_ids: binding_id_with_constraints.constraint_ids,
|
||||
},
|
||||
visibility_constraint: binding_id_with_constraints.visibility_constraint,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for BindingWithConstraintsIterator<'_, '_> {}
|
||||
|
||||
pub(crate) struct BindingWithConstraints<'map, 'db> {
|
||||
pub(crate) struct BindingWithConstraints<'db, I> {
|
||||
pub(crate) binding: Option<Definition<'db>>,
|
||||
pub(crate) constraints: ConstraintsIterator<'map, 'db>,
|
||||
pub(crate) constraints: I,
|
||||
pub(crate) visibility_constraint: ScopedVisibilityConstraintId,
|
||||
}
|
||||
|
||||
pub(crate) struct ConstraintsIterator<'map, 'db> {
|
||||
all_constraints: &'map AllConstraints<'db>,
|
||||
constraint_ids: ConstraintIdIterator<'map>,
|
||||
}
|
||||
|
||||
impl<'db> Iterator for ConstraintsIterator<'_, 'db> {
|
||||
type Item = Constraint<'db>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.constraint_ids
|
||||
.next()
|
||||
.map(|constraint_id| self.all_constraints[constraint_id])
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for ConstraintsIterator<'_, '_> {}
|
||||
|
||||
pub(crate) struct DeclarationsIterator<'map, 'db> {
|
||||
all_definitions: &'map IndexVec<ScopedDefinitionId, Option<Definition<'db>>>,
|
||||
pub(crate) visibility_constraints: &'map VisibilityConstraints<'db>,
|
||||
inner: DeclarationIdIterator<'map>,
|
||||
}
|
||||
|
||||
pub(crate) struct DeclarationWithConstraint<'db> {
|
||||
pub(crate) declaration: Option<Definition<'db>>,
|
||||
pub(crate) visibility_constraint: ScopedVisibilityConstraintId,
|
||||
}
|
||||
|
||||
impl<'db> Iterator for DeclarationsIterator<'_, 'db> {
|
||||
type Item = DeclarationWithConstraint<'db>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.inner.next().map(
|
||||
|DeclarationIdWithConstraint {
|
||||
definition,
|
||||
visibility_constraint,
|
||||
}| {
|
||||
DeclarationWithConstraint {
|
||||
declaration: self.all_definitions[definition],
|
||||
visibility_constraint,
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for DeclarationsIterator<'_, '_> {}
|
||||
|
||||
/// A snapshot of the definitions and constraints state at a particular point in control flow.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(super) struct FlowSnapshot {
|
||||
|
||||
@@ -48,7 +48,7 @@ use itertools::{EitherOrBoth, Itertools};
|
||||
use ruff_index::newtype_index;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::semantic_index::use_def::bitset::{BitSet, BitSetIterator};
|
||||
use crate::semantic_index::use_def::bitset::BitSet;
|
||||
use crate::semantic_index::use_def::VisibilityConstraints;
|
||||
|
||||
/// A newtype-index for a definition in a particular scope.
|
||||
@@ -73,14 +73,12 @@ const INLINE_BINDING_BLOCKS: usize = 3;
|
||||
|
||||
/// A [`BitSet`] of [`ScopedDefinitionId`], representing live bindings of a symbol in a scope.
|
||||
type Bindings = BitSet<INLINE_BINDING_BLOCKS>;
|
||||
type BindingsIterator<'a> = BitSetIterator<'a, INLINE_BINDING_BLOCKS>;
|
||||
|
||||
/// Can reference this * 64 total declarations inline; more will fall back to the heap.
|
||||
const INLINE_DECLARATION_BLOCKS: usize = 3;
|
||||
|
||||
/// A [`BitSet`] of [`ScopedDefinitionId`], representing live declarations of a symbol in a scope.
|
||||
type Declarations = BitSet<INLINE_DECLARATION_BLOCKS>;
|
||||
type DeclarationsIterator<'a> = BitSetIterator<'a, INLINE_DECLARATION_BLOCKS>;
|
||||
|
||||
/// Can reference this * 64 total constraints inline; more will fall back to the heap.
|
||||
const INLINE_CONSTRAINT_BLOCKS: usize = 2;
|
||||
@@ -96,9 +94,6 @@ type InlineConstraintArray = [Constraints; INLINE_BINDINGS_PER_SYMBOL];
|
||||
/// One [`BitSet`] of applicable [`ScopedConstraintId`]s per live binding.
|
||||
type ConstraintsPerBinding = SmallVec<InlineConstraintArray>;
|
||||
|
||||
/// Iterate over all constraints for a single binding.
|
||||
type ConstraintsIterator<'a> = std::slice::Iter<'a, Constraints>;
|
||||
|
||||
/// A newtype-index for a visibility constraint in a particular scope.
|
||||
#[newtype_index]
|
||||
pub(crate) struct ScopedVisibilityConstraintId;
|
||||
@@ -121,9 +116,6 @@ type VisibilityConstraintPerDeclaration = SmallVec<InlineVisibilityConstraintsAr
|
||||
/// One [`ScopedVisibilityConstraintId`] per live binding.
|
||||
type VisibilityConstraintPerBinding = SmallVec<InlineVisibilityConstraintsArray>;
|
||||
|
||||
/// Iterator over the visibility constraints for all live bindings/declarations.
|
||||
type VisibilityConstraintsIterator<'a> = std::slice::Iter<'a, ScopedVisibilityConstraintId>;
|
||||
|
||||
/// Live declarations for a single symbol at some point in control flow, with their
|
||||
/// corresponding visibility constraints.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
@@ -173,11 +165,15 @@ impl SymbolDeclarations {
|
||||
}
|
||||
|
||||
/// Return an iterator over live declarations for this symbol.
|
||||
pub(super) fn iter(&self) -> DeclarationIdIterator {
|
||||
DeclarationIdIterator {
|
||||
declarations: self.live_declarations.iter(),
|
||||
visibility_constraints: self.visibility_constraints.iter(),
|
||||
}
|
||||
pub(super) fn iter(&self) -> impl Iterator<Item = DeclarationIdWithConstraint> + '_ {
|
||||
(self.live_declarations.iter())
|
||||
.zip(self.visibility_constraints.iter())
|
||||
.map(
|
||||
|(declaration, &visibility_constraint)| DeclarationIdWithConstraint {
|
||||
definition: ScopedDefinitionId::from_u32(declaration),
|
||||
visibility_constraint,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn merge(&mut self, b: Self, visibility_constraints: &mut VisibilityConstraints) {
|
||||
@@ -279,12 +275,20 @@ impl SymbolBindings {
|
||||
}
|
||||
|
||||
/// Iterate over currently live bindings for this symbol
|
||||
pub(super) fn iter(&self) -> BindingIdWithConstraintsIterator {
|
||||
BindingIdWithConstraintsIterator {
|
||||
definitions: self.live_bindings.iter(),
|
||||
constraints: self.constraints.iter(),
|
||||
visibility_constraints: self.visibility_constraints.iter(),
|
||||
}
|
||||
pub(super) fn iter(
|
||||
&self,
|
||||
) -> impl Iterator<Item = BindingIdWithConstraints<impl Iterator<Item = ScopedConstraintId> + '_>> + '_
|
||||
{
|
||||
let i = (self.live_bindings.iter())
|
||||
.zip(self.constraints.iter())
|
||||
.zip(self.visibility_constraints.iter());
|
||||
i.map(
|
||||
|((def, constraints), visibility_constraint_id)| BindingIdWithConstraints {
|
||||
definition: ScopedDefinitionId::from_u32(def),
|
||||
constraint_ids: constraints.iter().map(ScopedConstraintId::from_u32),
|
||||
visibility_constraint: *visibility_constraint_id,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn merge(&mut self, mut b: Self, visibility_constraints: &mut VisibilityConstraints) {
|
||||
@@ -421,61 +425,12 @@ impl SymbolState {
|
||||
/// narrowing constraints ([`ScopedConstraintId`]) and a corresponding visibility
|
||||
/// visibility constraint ([`ScopedVisibilityConstraintId`]).
|
||||
#[derive(Debug)]
|
||||
pub(super) struct BindingIdWithConstraints<'map> {
|
||||
pub(super) struct BindingIdWithConstraints<I> {
|
||||
pub(super) definition: ScopedDefinitionId,
|
||||
pub(super) constraint_ids: ConstraintIdIterator<'map>,
|
||||
pub(super) constraint_ids: I,
|
||||
pub(super) visibility_constraint: ScopedVisibilityConstraintId,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct BindingIdWithConstraintsIterator<'map> {
|
||||
definitions: BindingsIterator<'map>,
|
||||
constraints: ConstraintsIterator<'map>,
|
||||
visibility_constraints: VisibilityConstraintsIterator<'map>,
|
||||
}
|
||||
|
||||
impl<'map> Iterator for BindingIdWithConstraintsIterator<'map> {
|
||||
type Item = BindingIdWithConstraints<'map>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match (
|
||||
self.definitions.next(),
|
||||
self.constraints.next(),
|
||||
self.visibility_constraints.next(),
|
||||
) {
|
||||
(None, None, None) => None,
|
||||
(Some(def), Some(constraints), Some(visibility_constraint_id)) => {
|
||||
Some(BindingIdWithConstraints {
|
||||
definition: ScopedDefinitionId::from_u32(def),
|
||||
constraint_ids: ConstraintIdIterator {
|
||||
wrapped: constraints.iter(),
|
||||
},
|
||||
visibility_constraint: *visibility_constraint_id,
|
||||
})
|
||||
}
|
||||
// SAFETY: see above.
|
||||
_ => unreachable!("definitions and constraints length mismatch"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for BindingIdWithConstraintsIterator<'_> {}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct ConstraintIdIterator<'a> {
|
||||
wrapped: BitSetIterator<'a, INLINE_CONSTRAINT_BLOCKS>,
|
||||
}
|
||||
|
||||
impl Iterator for ConstraintIdIterator<'_> {
|
||||
type Item = ScopedConstraintId;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.wrapped.next().map(ScopedConstraintId::from_u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for ConstraintIdIterator<'_> {}
|
||||
|
||||
/// A single declaration (as [`ScopedDefinitionId`]) with a corresponding visibility
|
||||
/// visibility constraint ([`ScopedVisibilityConstraintId`]).
|
||||
#[derive(Debug)]
|
||||
@@ -484,31 +439,6 @@ pub(super) struct DeclarationIdWithConstraint {
|
||||
pub(super) visibility_constraint: ScopedVisibilityConstraintId,
|
||||
}
|
||||
|
||||
pub(super) struct DeclarationIdIterator<'map> {
|
||||
pub(crate) declarations: DeclarationsIterator<'map>,
|
||||
pub(crate) visibility_constraints: VisibilityConstraintsIterator<'map>,
|
||||
}
|
||||
|
||||
impl Iterator for DeclarationIdIterator<'_> {
|
||||
type Item = DeclarationIdWithConstraint;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match (self.declarations.next(), self.visibility_constraints.next()) {
|
||||
(None, None) => None,
|
||||
(Some(declaration), Some(&visibility_constraint)) => {
|
||||
Some(DeclarationIdWithConstraint {
|
||||
definition: ScopedDefinitionId::from_u32(declaration),
|
||||
visibility_constraint,
|
||||
})
|
||||
}
|
||||
// SAFETY: see above.
|
||||
_ => unreachable!("declarations and visibility_constraints length mismatch"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::iter::FusedIterator for DeclarationIdIterator<'_> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -214,7 +214,7 @@ fn check_unused_suppressions(context: &mut CheckSuppressionsContext) {
|
||||
);
|
||||
|
||||
// Collect all suppressions that are unused after type-checking.
|
||||
for suppression in all {
|
||||
for suppression in all.iter() {
|
||||
if context.diagnostics.is_used(suppression.id()) {
|
||||
continue;
|
||||
}
|
||||
@@ -401,23 +401,11 @@ impl Suppressions {
|
||||
})
|
||||
}
|
||||
|
||||
fn iter(&self) -> SuppressionsIter {
|
||||
fn iter(&self) -> impl Iterator<Item = &Suppression> + '_ {
|
||||
self.file.iter().chain(&self.line)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type SuppressionsIter<'a> =
|
||||
std::iter::Chain<std::slice::Iter<'a, Suppression>, std::slice::Iter<'a, Suppression>>;
|
||||
|
||||
impl<'a> IntoIterator for &'a Suppressions {
|
||||
type Item = &'a Suppression;
|
||||
type IntoIter = SuppressionsIter<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// A `type: ignore` or `knot: ignore` suppression.
|
||||
///
|
||||
/// Suppression comments that suppress multiple codes
|
||||
|
||||
@@ -23,12 +23,12 @@ pub use self::subclass_of::SubclassOfType;
|
||||
use crate::module_name::ModuleName;
|
||||
use crate::module_resolver::{file_to_module, resolve_module, KnownModule};
|
||||
use crate::semantic_index::ast_ids::HasScopedExpressionId;
|
||||
use crate::semantic_index::constraint::Constraint;
|
||||
use crate::semantic_index::definition::Definition;
|
||||
use crate::semantic_index::symbol::{self as symbol, ScopeId, ScopedSymbolId};
|
||||
use crate::semantic_index::{
|
||||
global_scope, imported_modules, semantic_index, symbol_table, use_def_map,
|
||||
BindingWithConstraints, BindingWithConstraintsIterator, DeclarationWithConstraint,
|
||||
DeclarationsIterator,
|
||||
BindingWithConstraints, DeclarationWithConstraint, UseDefMap,
|
||||
};
|
||||
use crate::stdlib::{builtins_symbol, known_module_symbol, typing_extensions_symbol};
|
||||
use crate::suppression::check_suppressions;
|
||||
@@ -118,7 +118,7 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
|
||||
// on inference from bindings.
|
||||
|
||||
let declarations = use_def.public_declarations(symbol_id);
|
||||
let declared = symbol_from_declarations(db, declarations);
|
||||
let declared = symbol_from_declarations(db, use_def.as_ref(), declarations);
|
||||
let is_final = declared.as_ref().is_ok_and(SymbolAndQualifiers::is_final);
|
||||
let declared = declared.map(|SymbolAndQualifiers(symbol, _)| symbol);
|
||||
|
||||
@@ -128,7 +128,7 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
|
||||
// Symbol is possibly declared
|
||||
Ok(Symbol::Type(declared_ty, Boundness::PossiblyUnbound)) => {
|
||||
let bindings = use_def.public_bindings(symbol_id);
|
||||
let inferred = symbol_from_bindings(db, bindings);
|
||||
let inferred = symbol_from_bindings(db, use_def.as_ref(), bindings);
|
||||
|
||||
match inferred {
|
||||
// Symbol is possibly undeclared and definitely unbound
|
||||
@@ -148,7 +148,7 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
|
||||
// Symbol is undeclared, return the union of `Unknown` with the inferred type
|
||||
Ok(Symbol::Unbound) => {
|
||||
let bindings = use_def.public_bindings(symbol_id);
|
||||
let inferred = symbol_from_bindings(db, bindings);
|
||||
let inferred = symbol_from_bindings(db, use_def.as_ref(), bindings);
|
||||
|
||||
widen_type_for_undeclared_public_symbol(db, inferred, is_dunder_slots || is_final)
|
||||
}
|
||||
@@ -321,11 +321,14 @@ fn definition_expression_type<'db>(
|
||||
/// together with boundness information in a [`Symbol`].
|
||||
///
|
||||
/// The type will be a union if there are multiple bindings with different types.
|
||||
fn symbol_from_bindings<'db>(
|
||||
fn symbol_from_bindings<'map, 'db: 'map>(
|
||||
db: &'db dyn Db,
|
||||
bindings_with_constraints: BindingWithConstraintsIterator<'_, 'db>,
|
||||
use_def: &UseDefMap<'map>,
|
||||
bindings_with_constraints: impl Iterator<
|
||||
Item = BindingWithConstraints<'db, impl Iterator<Item = Constraint<'db>>>,
|
||||
>,
|
||||
) -> Symbol<'db> {
|
||||
let visibility_constraints = bindings_with_constraints.visibility_constraints;
|
||||
let visibility_constraints = &use_def.visibility_constraints;
|
||||
let mut bindings_with_constraints = bindings_with_constraints.peekable();
|
||||
|
||||
let unbound_visibility = if let Some(BindingWithConstraints {
|
||||
@@ -433,7 +436,7 @@ impl<'db> From<Type<'db>> for SymbolAndQualifiers<'db> {
|
||||
type SymbolFromDeclarationsResult<'db> =
|
||||
Result<SymbolAndQualifiers<'db>, (TypeAndQualifiers<'db>, Box<[Type<'db>]>)>;
|
||||
|
||||
/// Build a declared type from a [`DeclarationsIterator`].
|
||||
/// Build a declared type from an iterator of [`DeclarationWithConstraint`]s.
|
||||
///
|
||||
/// If there is only one declaration, or all declarations declare the same type, returns
|
||||
/// `Ok(..)`. If there are conflicting declarations, returns an `Err(..)` variant with
|
||||
@@ -443,9 +446,10 @@ type SymbolFromDeclarationsResult<'db> =
|
||||
/// [`TypeQualifiers`] that have been specified on the declaration(s).
|
||||
fn symbol_from_declarations<'db>(
|
||||
db: &'db dyn Db,
|
||||
declarations: DeclarationsIterator<'_, 'db>,
|
||||
use_def: &UseDefMap,
|
||||
declarations: impl Iterator<Item = DeclarationWithConstraint<'db>>,
|
||||
) -> SymbolFromDeclarationsResult<'db> {
|
||||
let visibility_constraints = declarations.visibility_constraints;
|
||||
let visibility_constraints = &use_def.visibility_constraints;
|
||||
let mut declarations = declarations.peekable();
|
||||
|
||||
let undeclared_visibility = if let Some(DeclarationWithConstraint {
|
||||
@@ -4126,7 +4130,7 @@ impl<'db> Class<'db> {
|
||||
|
||||
let declarations = use_def.public_declarations(symbol_id);
|
||||
|
||||
match symbol_from_declarations(db, declarations) {
|
||||
match symbol_from_declarations(db, use_def.as_ref(), declarations) {
|
||||
Ok(SymbolAndQualifiers(Symbol::Type(declared_ty, _), qualifiers)) => {
|
||||
if let Some(function) = declared_ty.into_function_literal() {
|
||||
// TODO: Eventually, we are going to process all decorators correctly. This is
|
||||
@@ -4143,7 +4147,7 @@ impl<'db> Class<'db> {
|
||||
}
|
||||
Ok(symbol @ SymbolAndQualifiers(Symbol::Unbound, qualifiers)) => {
|
||||
let bindings = use_def.public_bindings(symbol_id);
|
||||
let inferred = symbol_from_bindings(db, bindings);
|
||||
let inferred = symbol_from_bindings(db, use_def.as_ref(), bindings);
|
||||
|
||||
SymbolAndQualifiers(
|
||||
widen_type_for_undeclared_public_symbol(db, inferred, symbol.is_final()),
|
||||
|
||||
@@ -862,7 +862,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
let use_def = self.index.use_def_map(binding.file_scope(self.db()));
|
||||
let declarations = use_def.declarations_at_binding(binding);
|
||||
let mut bound_ty = ty;
|
||||
let declared_ty = symbol_from_declarations(self.db(), declarations)
|
||||
let declared_ty = symbol_from_declarations(self.db(), use_def.as_ref(), declarations)
|
||||
.map(|SymbolAndQualifiers(s, _)| s.ignore_possibly_unbound().unwrap_or(Type::unknown()))
|
||||
.unwrap_or_else(|(ty, conflicting)| {
|
||||
// TODO point out the conflicting declarations in the diagnostic?
|
||||
@@ -897,7 +897,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
let use_def = self.index.use_def_map(declaration.file_scope(self.db()));
|
||||
let prior_bindings = use_def.bindings_at_declaration(declaration);
|
||||
// unbound_ty is Never because for this check we don't care about unbound
|
||||
let inferred_ty = symbol_from_bindings(self.db(), prior_bindings)
|
||||
let inferred_ty = symbol_from_bindings(self.db(), use_def.as_ref(), prior_bindings)
|
||||
.ignore_possibly_unbound()
|
||||
.unwrap_or(Type::Never);
|
||||
let ty = if inferred_ty.is_assignable_to(self.db(), ty.inner_type()) {
|
||||
@@ -3362,7 +3362,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
// If we're inferring types of deferred expressions, always treat them as public symbols
|
||||
let inferred = if self.is_deferred() {
|
||||
if let Some(symbol) = self.index.symbol_table(file_scope_id).symbol_id_by_name(id) {
|
||||
symbol_from_bindings(self.db(), use_def.public_bindings(symbol))
|
||||
symbol_from_bindings(self.db(), use_def.as_ref(), use_def.public_bindings(symbol))
|
||||
} else {
|
||||
assert!(
|
||||
self.deferred_state.in_string_annotation(),
|
||||
@@ -3372,7 +3372,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||
}
|
||||
} else {
|
||||
let use_id = name.scoped_use_id(self.db(), self.scope());
|
||||
symbol_from_bindings(self.db(), use_def.bindings_at_use(use_id))
|
||||
symbol_from_bindings(self.db(), use_def.as_ref(), use_def.bindings_at_use(use_id))
|
||||
};
|
||||
|
||||
if let Symbol::Type(ty, Boundness::Bound) = inferred {
|
||||
|
||||
Reference in New Issue
Block a user