Compare commits

...

2 Commits

Author SHA1 Message Date
Micha Reiser
56cb92f486 Map directly to UseId 2025-07-12 12:58:23 +02:00
Micha Reiser
d6b1081898 [ty] Move ScopedUseId to UseDefMap 2025-07-12 12:43:11 +02:00
10 changed files with 123 additions and 223 deletions

View File

@@ -1,4 +1,4 @@
use ruff_python_ast::{HasNodeIndex, NodeIndex};
use ruff_python_ast::{self as ast, HasNodeIndex, NodeIndex};
/// Compact key for a node for use in a hash map.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, get_size2::GetSize)]
@@ -12,3 +12,31 @@ impl NodeKey {
NodeKey(node.node_index().load())
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, salsa::Update, get_size2::GetSize)]
pub(crate) struct ExpressionNodeKey(NodeKey);
// TODO: Delete after merging https://github.com/astral-sh/ruff/pull/19025
impl From<&ast::Identifier> for ExpressionNodeKey {
fn from(value: &ast::Identifier) -> Self {
Self(NodeKey::from_node(value))
}
}
impl From<ast::ExprRef<'_>> for ExpressionNodeKey {
fn from(value: ast::ExprRef<'_>) -> Self {
Self(NodeKey::from_node(value))
}
}
impl From<&ast::Expr> for ExpressionNodeKey {
fn from(value: &ast::Expr) -> Self {
Self(NodeKey::from_node(value))
}
}
impl From<&ast::ExprCall> for ExpressionNodeKey {
fn from(value: &ast::ExprCall) -> Self {
Self(NodeKey::from_node(value))
}
}

View File

@@ -12,9 +12,7 @@ use salsa::plumbing::AsId;
use crate::Db;
use crate::module_name::ModuleName;
use crate::node_key::NodeKey;
use crate::semantic_index::ast_ids::AstIds;
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
use crate::node_key::{ExpressionNodeKey, NodeKey};
use crate::semantic_index::builder::SemanticIndexBuilder;
use crate::semantic_index::definition::{Definition, DefinitionNodeKey, Definitions};
use crate::semantic_index::expression::Expression;
@@ -24,9 +22,9 @@ use crate::semantic_index::place::{
ScopeKind, ScopedPlaceId,
};
use crate::semantic_index::use_def::{EagerSnapshotKey, ScopedEagerSnapshotId, UseDefMap};
pub(crate) use crate::semantic_index::use_def::{FileUseId, HasFileUseId};
use crate::util::get_size::untracked_arc_size;
pub mod ast_ids;
mod builder;
pub mod definition;
pub mod expression;
@@ -220,12 +218,6 @@ pub(crate) struct SemanticIndex<'db> {
/// Use-def map for each scope in this file.
use_def_maps: IndexVec<FileScopeId, ArcUseDefMap<'db>>,
/// Lookup table to map between node ids and ast nodes.
///
/// Note: We should not depend on this map when analysing other files or
/// changing a file invalidates all dependents.
ast_ids: IndexVec<FileScopeId, AstIds>,
/// The set of modules that are imported anywhere within this file.
imported_modules: Arc<FxHashSet<ModuleName>>,
@@ -261,11 +253,6 @@ impl<'db> SemanticIndex<'db> {
self.use_def_maps[scope_id].clone()
}
#[track_caller]
pub(crate) fn ast_ids(&self, scope_id: FileScopeId) -> &AstIds {
&self.ast_ids[scope_id]
}
/// Returns the ID of the `expression`'s enclosing scope.
#[track_caller]
pub(crate) fn expression_scope_id(
@@ -623,11 +610,12 @@ mod tests {
use crate::Db;
use crate::db::tests::{TestDb, TestDbBuilder};
use crate::semantic_index::ast_ids::{HasScopedUseId, ScopedUseId};
use crate::semantic_index::definition::{Definition, DefinitionKind};
use crate::semantic_index::place::{FileScopeId, PlaceTable, Scope, ScopeKind, ScopedPlaceId};
use crate::semantic_index::use_def::UseDefMap;
use crate::semantic_index::{global_scope, place_table, semantic_index, use_def_map};
use crate::semantic_index::{
FileUseId, HasFileUseId, global_scope, place_table, semantic_index, use_def_map,
};
impl UseDefMap<'_> {
fn first_public_binding(&self, symbol: ScopedPlaceId) -> Option<Definition<'_>> {
@@ -635,8 +623,8 @@ mod tests {
.find_map(|constrained_binding| constrained_binding.binding.definition())
}
fn first_binding_at_use(&self, use_id: ScopedUseId) -> Option<Definition<'_>> {
self.bindings_at_use(use_id)
fn first_binding_at_use(&self, use_id: FileUseId) -> Option<Definition<'_>> {
self.bindings_for_node(use_id)
.find_map(|constrained_binding| constrained_binding.binding.definition())
}
}
@@ -1059,8 +1047,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
.elt
.as_name_expr()
.unwrap();
let element_use_id =
element.scoped_use_id(&db, comprehension_scope_id.to_scope_id(&db, file));
let element_use_id = element.use_id();
let binding = use_def.first_binding_at_use(element_use_id).unwrap();
let DefinitionKind::Comprehension(comprehension) = binding.kind(&db) else {
@@ -1334,7 +1321,7 @@ class C[T]:
let ast::Expr::Name(x_use_expr_name) = x_use_expr.as_ref() else {
panic!("expected a Name");
};
let x_use_id = x_use_expr_name.scoped_use_id(&db, scope);
let x_use_id = x_use_expr_name.use_id();
let use_def = use_def_map(&db, scope);
let binding = use_def.first_binding_at_use(x_use_id).unwrap();
let DefinitionKind::Assignment(assignment) = binding.kind(&db) else {

View File

@@ -1,144 +0,0 @@
use rustc_hash::FxHashMap;
use ruff_index::newtype_index;
use ruff_python_ast as ast;
use ruff_python_ast::ExprRef;
use crate::Db;
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
use crate::semantic_index::place::ScopeId;
use crate::semantic_index::semantic_index;
/// AST ids for a single scope.
///
/// The motivation for building the AST ids per scope isn't about reducing invalidation because
/// the struct changes whenever the parsed AST changes. Instead, it's mainly that we can
/// build the AST ids struct when building the place table and also keep the property that
/// IDs of outer scopes are unaffected by changes in inner scopes.
///
/// For example, we don't want that adding new statements to `foo` changes the statement id of `x = foo()` in:
///
/// ```python
/// def foo():
/// return 5
///
/// x = foo()
/// ```
#[derive(Debug, salsa::Update, get_size2::GetSize)]
pub(crate) struct AstIds {
/// Maps expressions which "use" a place (that is, [`ast::ExprName`], [`ast::ExprAttribute`] or [`ast::ExprSubscript`]) to a use id.
uses_map: FxHashMap<ExpressionNodeKey, ScopedUseId>,
}
impl AstIds {
fn use_id(&self, key: impl Into<ExpressionNodeKey>) -> ScopedUseId {
self.uses_map[&key.into()]
}
}
fn ast_ids<'db>(db: &'db dyn Db, scope: ScopeId) -> &'db AstIds {
semantic_index(db, scope.file(db)).ast_ids(scope.file_scope_id(db))
}
/// Uniquely identifies a use of a name in a [`crate::semantic_index::place::FileScopeId`].
#[newtype_index]
#[derive(get_size2::GetSize)]
pub struct ScopedUseId;
pub trait HasScopedUseId {
/// Returns the ID that uniquely identifies the use in `scope`.
fn scoped_use_id(&self, db: &dyn Db, scope: ScopeId) -> ScopedUseId;
}
impl HasScopedUseId for ast::Identifier {
fn scoped_use_id(&self, db: &dyn Db, scope: ScopeId) -> ScopedUseId {
let ast_ids = ast_ids(db, scope);
ast_ids.use_id(self)
}
}
impl HasScopedUseId for ast::ExprName {
fn scoped_use_id(&self, db: &dyn Db, scope: ScopeId) -> ScopedUseId {
let expression_ref = ExprRef::from(self);
expression_ref.scoped_use_id(db, scope)
}
}
impl HasScopedUseId for ast::ExprAttribute {
fn scoped_use_id(&self, db: &dyn Db, scope: ScopeId) -> ScopedUseId {
let expression_ref = ExprRef::from(self);
expression_ref.scoped_use_id(db, scope)
}
}
impl HasScopedUseId for ast::ExprSubscript {
fn scoped_use_id(&self, db: &dyn Db, scope: ScopeId) -> ScopedUseId {
let expression_ref = ExprRef::from(self);
expression_ref.scoped_use_id(db, scope)
}
}
impl HasScopedUseId for ast::ExprRef<'_> {
fn scoped_use_id(&self, db: &dyn Db, scope: ScopeId) -> ScopedUseId {
let ast_ids = ast_ids(db, scope);
ast_ids.use_id(*self)
}
}
#[derive(Debug, Default)]
pub(super) struct AstIdsBuilder {
uses_map: FxHashMap<ExpressionNodeKey, ScopedUseId>,
}
impl AstIdsBuilder {
/// Adds `expr` to the use ids map and returns its id.
pub(super) fn record_use(&mut self, expr: impl Into<ExpressionNodeKey>) -> ScopedUseId {
let use_id = self.uses_map.len().into();
self.uses_map.insert(expr.into(), use_id);
use_id
}
pub(super) fn finish(mut self) -> AstIds {
self.uses_map.shrink_to_fit();
AstIds {
uses_map: self.uses_map,
}
}
}
/// Node key that can only be constructed for expressions.
pub(crate) mod node_key {
use ruff_python_ast as ast;
use crate::node_key::NodeKey;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, salsa::Update, get_size2::GetSize)]
pub(crate) struct ExpressionNodeKey(NodeKey);
impl From<ast::ExprRef<'_>> for ExpressionNodeKey {
fn from(value: ast::ExprRef<'_>) -> Self {
Self(NodeKey::from_node(value))
}
}
impl From<&ast::Expr> for ExpressionNodeKey {
fn from(value: &ast::Expr) -> Self {
Self(NodeKey::from_node(value))
}
}
impl From<&ast::ExprCall> for ExpressionNodeKey {
fn from(value: &ast::ExprCall) -> Self {
Self(NodeKey::from_node(value))
}
}
impl From<&ast::Identifier> for ExpressionNodeKey {
fn from(value: &ast::Identifier) -> Self {
Self(NodeKey::from_node(value))
}
}
}

View File

@@ -19,9 +19,8 @@ use ruff_text_size::TextRange;
use crate::ast_node_ref::AstNodeRef;
use crate::module_name::ModuleName;
use crate::module_resolver::resolve_module;
use crate::node_key::NodeKey;
use crate::semantic_index::ast_ids::AstIdsBuilder;
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
use crate::node_key::{ExpressionNodeKey, NodeKey};
use crate::semantic_index::definition::{
AnnotatedAssignmentDefinitionNodeRef, AssignmentDefinitionNodeRef,
ComprehensionDefinitionNodeRef, Definition, DefinitionCategory, DefinitionNodeKey,
@@ -45,7 +44,7 @@ use crate::semantic_index::reachability_constraints::{
use crate::semantic_index::use_def::{
EagerSnapshotKey, FlowSnapshot, ScopedEagerSnapshotId, UseDefMapBuilder,
};
use crate::semantic_index::{ArcUseDefMap, SemanticIndex};
use crate::semantic_index::{ArcUseDefMap, HasFileUseId, SemanticIndex};
use crate::unpack::{Unpack, UnpackKind, UnpackPosition, UnpackValue};
use crate::{Db, Program};
@@ -99,7 +98,6 @@ pub(super) struct SemanticIndexBuilder<'db, 'ast> {
scopes: IndexVec<FileScopeId, Scope>,
scope_ids_by_scope: IndexVec<FileScopeId, ScopeId<'db>>,
place_tables: IndexVec<FileScopeId, PlaceTableBuilder>,
ast_ids: IndexVec<FileScopeId, AstIdsBuilder>,
use_def_maps: IndexVec<FileScopeId, UseDefMapBuilder<'db>>,
scopes_by_node: FxHashMap<NodeWithScopeKey, FileScopeId>,
scopes_by_expression: FxHashMap<ExpressionNodeKey, FileScopeId>,
@@ -132,7 +130,6 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
scopes: IndexVec::new(),
place_tables: IndexVec::new(),
ast_ids: IndexVec::new(),
scope_ids_by_scope: IndexVec::new(),
use_def_maps: IndexVec::new(),
@@ -255,7 +252,6 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
self.place_tables.push(PlaceTableBuilder::default());
self.use_def_maps
.push(UseDefMapBuilder::new(is_class_scope));
let ast_id_scope = self.ast_ids.push(AstIdsBuilder::default());
let scope_id = ScopeId::new(self.db, self.file, file_scope_id);
@@ -263,8 +259,6 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
let previous = self.scopes_by_node.insert(node.node_key(), file_scope_id);
debug_assert_eq!(previous, None);
debug_assert_eq!(ast_id_scope, file_scope_id);
self.scope_stack.push(ScopeInfo {
file_scope_id,
current_loop: None,
@@ -372,11 +366,6 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
&mut self.use_def_maps[scope_id].reachability_constraints
}
fn current_ast_ids(&mut self) -> &mut AstIdsBuilder {
let scope_id = self.current_scope();
&mut self.ast_ids[scope_id]
}
fn flow_snapshot(&self) -> FlowSnapshot {
self.current_use_def_map().snapshot()
}
@@ -1028,16 +1017,9 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
.map(|builder| ArcUseDefMap::new(builder.finish()))
.collect();
let mut ast_ids: IndexVec<_, _> = self
.ast_ids
.into_iter()
.map(super::ast_ids::AstIdsBuilder::finish)
.collect();
self.scopes.shrink_to_fit();
place_tables.shrink_to_fit();
use_def_maps.shrink_to_fit();
ast_ids.shrink_to_fit();
self.scopes_by_expression.shrink_to_fit();
self.definitions_by_node.shrink_to_fit();
@@ -1052,7 +1034,6 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
definitions_by_node: self.definitions_by_node,
expressions_by_node: self.expressions_by_node,
scope_ids_by_scope: self.scope_ids_by_scope,
ast_ids,
scopes_by_expression: self.scopes_by_expression,
scopes_by_node: self.scopes_by_node,
use_def_maps,
@@ -1144,9 +1125,11 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
// done on the `Identifier` node as opposed to `ExprName` because that's what the
// AST uses.
self.mark_place_used(symbol);
let use_id = self.current_ast_ids().record_use(name);
self.current_use_def_map_mut()
.record_use(symbol, use_id, NodeKey::from_node(name));
self.current_use_def_map_mut().record_use(
symbol,
name.use_id(),
NodeKey::from_node(name),
);
self.add_definition(symbol, function_def);
}
@@ -2053,8 +2036,14 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
let place_id = self.add_place(place_expr);
if is_use {
let use_id = match expr {
ast::Expr::Name(name) => name.use_id(),
ast::Expr::Attribute(attribute) => attribute.use_id(),
ast::Expr::Subscript(subscript) => subscript.use_id(),
_ => unreachable!(),
};
self.mark_place_used(place_id);
let use_id = self.current_ast_ids().record_use(expr);
self.current_use_def_map_mut()
.record_use(place_id, use_id, node_key);
}

View File

@@ -29,9 +29,9 @@
//! [`Predicate`]: crate::semantic_index::predicate::Predicate
use crate::list::{List, ListBuilder, ListSetReverseIterator, ListStorage};
use crate::semantic_index::ast_ids::ScopedUseId;
use crate::semantic_index::place::FileScopeId;
use crate::semantic_index::predicate::ScopedPredicateId;
use crate::semantic_index::use_def::FileUseId;
/// A narrowing constraint associated with a live binding.
///
@@ -44,7 +44,7 @@ pub(crate) type ScopedNarrowingConstraint = List<ScopedNarrowingConstraintPredic
pub(crate) enum ConstraintKey {
NarrowingConstraint(ScopedNarrowingConstraint),
EagerNestedScope(FileScopeId),
UseId(ScopedUseId),
UseId(FileUseId),
}
/// One of the [`Predicate`]s in a narrowing constraint, which constraints the type of the

View File

@@ -241,6 +241,7 @@
//! visits a `StmtIf` node.
use ruff_index::{IndexVec, newtype_index};
use ruff_python_ast as ast;
use rustc_hash::FxHashMap;
use self::place_state::{
@@ -249,7 +250,6 @@ use self::place_state::{
};
use crate::node_key::NodeKey;
use crate::place::BoundnessAnalysis;
use crate::semantic_index::ast_ids::ScopedUseId;
use crate::semantic_index::definition::{Definition, DefinitionState};
use crate::semantic_index::narrowing_constraints::{
ConstraintKey, NarrowingConstraints, NarrowingConstraintsBuilder, NarrowingConstraintsIterator,
@@ -285,8 +285,8 @@ pub(crate) struct UseDefMap<'db> {
/// Array of reachability constraints in this scope.
reachability_constraints: ReachabilityConstraints,
/// [`Bindings`] reaching a [`ScopedUseId`].
bindings_by_use: IndexVec<ScopedUseId, Bindings>,
/// [`Bindings`] reaching a [`FileUseId`].
bindings_by_use: FxHashMap<FileUseId, Bindings>,
/// Tracks whether or not a given AST node is reachable from the start of the scope.
node_reachability: FxHashMap<NodeKey, ScopedReachabilityConstraintId>,
@@ -347,12 +347,13 @@ pub(crate) enum ApplicableConstraints<'map, 'db> {
}
impl<'db> UseDefMap<'db> {
pub(crate) fn bindings_at_use(
#[track_caller]
pub(crate) fn bindings_for_node(
&self,
use_id: ScopedUseId,
use_id: FileUseId,
) -> BindingWithConstraintsIterator<'_, 'db> {
self.bindings_iterator(
&self.bindings_by_use[use_id],
&self.bindings_by_use[&use_id],
BoundnessAnalysis::BasedOnUnboundVisibility,
)
}
@@ -382,7 +383,7 @@ impl<'db> UseDefMap<'db> {
ApplicableConstraints::ConstrainedBindings(bindings)
}
ConstraintKey::UseId(use_id) => {
ApplicableConstraints::ConstrainedBindings(self.bindings_at_use(use_id))
ApplicableConstraints::ConstrainedBindings(self.bindings_for_node(use_id))
}
}
}
@@ -735,7 +736,7 @@ pub(super) struct UseDefMapBuilder<'db> {
pub(super) reachability_constraints: ReachabilityConstraintsBuilder,
/// Live bindings at each so-far-recorded use.
bindings_by_use: IndexVec<ScopedUseId, Bindings>,
bindings_by_use: FxHashMap<FileUseId, Bindings>,
/// Tracks whether or not the current point in control flow is reachable from the
/// start of the scope.
@@ -771,7 +772,7 @@ impl<'db> UseDefMapBuilder<'db> {
predicates: PredicatesBuilder::default(),
narrowing_constraints: NarrowingConstraintsBuilder::default(),
reachability_constraints: ReachabilityConstraintsBuilder::default(),
bindings_by_use: IndexVec::new(),
bindings_by_use: FxHashMap::default(),
reachability: ScopedReachabilityConstraintId::ALWAYS_TRUE,
node_reachability: FxHashMap::default(),
declarations_by_binding: FxHashMap::default(),
@@ -1003,23 +1004,24 @@ impl<'db> UseDefMapBuilder<'db> {
pub(super) fn record_use(
&mut self,
place: ScopedPlaceId,
use_id: ScopedUseId,
use_id: FileUseId,
node_key: NodeKey,
) {
// We have a use of a place; clone the current bindings for that place, and record them
// as the live bindings for this use.
let new_use = self
let old_use = self
.bindings_by_use
.push(self.place_states[place].bindings().clone());
debug_assert_eq!(use_id, new_use);
.insert(use_id, self.place_states[place].bindings().clone());
debug_assert_eq!(old_use, None);
// Track reachability of all uses of places to silence `unresolved-reference`
// diagnostics in unreachable code.
self.record_node_reachability(node_key);
}
pub(super) fn record_node_reachability(&mut self, node_key: NodeKey) {
self.node_reachability.insert(node_key, self.reachability);
pub(super) fn record_node_reachability(&mut self, node: NodeKey) {
self.node_reachability.insert(node, self.reachability);
}
pub(super) fn snapshot_eager_state(
@@ -1144,3 +1146,42 @@ impl<'db> UseDefMapBuilder<'db> {
}
}
}
/// Uniquely identifies a use of a name in a [`crate::semantic_index::place::FileScopeId`].
#[derive(get_size2::GetSize, Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub(crate) struct FileUseId(NodeKey);
pub(crate) trait HasFileUseId {
/// Returns the ID that uniquely identifies the use in `scope`.
fn use_id(&self) -> FileUseId;
}
impl HasFileUseId for ast::Identifier {
fn use_id(&self) -> FileUseId {
FileUseId(NodeKey::from_node(self))
}
}
impl HasFileUseId for ast::ExprName {
fn use_id(&self) -> FileUseId {
FileUseId(NodeKey::from_node(self))
}
}
impl HasFileUseId for ast::ExprAttribute {
fn use_id(&self) -> FileUseId {
FileUseId(NodeKey::from_node(self))
}
}
impl HasFileUseId for ast::ExprSubscript {
fn use_id(&self) -> FileUseId {
FileUseId(NodeKey::from_node(self))
}
}
impl HasFileUseId for ast::ExprRef<'_> {
fn use_id(&self) -> FileUseId {
FileUseId(NodeKey::from_node(self))
}
}

View File

@@ -1,6 +1,6 @@
use ruff_db::files::{File, FilePath};
use ruff_db::source::line_index;
use ruff_python_ast as ast;
use ruff_python_ast::{self as ast};
use ruff_python_ast::{Expr, ExprRef, name::Name};
use ruff_source_file::LineIndex;

View File

@@ -60,10 +60,9 @@ use ruff_text_size::Ranged;
use crate::module_resolver::{KnownModule, file_to_module};
use crate::place::{Boundness, Place, place_from_bindings};
use crate::semantic_index::ast_ids::HasScopedUseId;
use crate::semantic_index::definition::Definition;
use crate::semantic_index::place::ScopeId;
use crate::semantic_index::semantic_index;
use crate::semantic_index::{HasFileUseId, semantic_index};
use crate::types::context::InferContext;
use crate::types::diagnostic::{
REDUNDANT_CAST, STATIC_ASSERT_ERROR, TYPE_ASSERTION_FAILURE,
@@ -293,10 +292,10 @@ impl<'db> OverloadLiteral<'db> {
.node(db)
.expect_function(&module)
.name
.scoped_use_id(db, scope);
.use_id();
let Place::Type(Type::FunctionLiteral(previous_type), Boundness::Bound) =
place_from_bindings(db, use_def.bindings_at_use(use_id))
place_from_bindings(db, use_def.bindings_for_node(use_id))
else {
return None;
};

View File

@@ -63,15 +63,14 @@ use super::subclass_of::SubclassOfInner;
use super::{ClassBase, NominalInstanceType, add_inferred_python_version_hint_to_diagnostic};
use crate::module_name::{ModuleName, ModuleNameResolutionError};
use crate::module_resolver::resolve_module;
use crate::node_key::NodeKey;
use crate::node_key::{ExpressionNodeKey, NodeKey};
use crate::place::{
Boundness, ConsideredDefinitions, LookupError, Place, PlaceAndQualifiers,
builtins_module_scope, builtins_symbol, explicit_global_symbol, global_symbol,
module_type_implicit_global_declaration, module_type_implicit_global_symbol, place,
place_from_bindings, place_from_declarations, typing_extensions_symbol,
};
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
use crate::semantic_index::ast_ids::{HasScopedUseId, ScopedUseId};
use crate::semantic_index::definition::{
AnnotatedAssignmentDefinitionKind, AssignmentDefinitionKind, ComprehensionDefinitionKind,
Definition, DefinitionKind, DefinitionNodeKey, DefinitionState, ExceptHandlerDefinitionKind,
@@ -83,7 +82,8 @@ use crate::semantic_index::place::{
FileScopeId, NodeWithScopeKind, NodeWithScopeRef, PlaceExpr, ScopeId, ScopeKind, ScopedPlaceId,
};
use crate::semantic_index::{
ApplicableConstraints, EagerSnapshotResult, SemanticIndex, place_table, semantic_index,
ApplicableConstraints, EagerSnapshotResult, FileUseId, HasFileUseId, SemanticIndex,
place_table, semantic_index,
};
use crate::types::call::{Binding, Bindings, CallArgumentTypes, CallArguments, CallError};
use crate::types::class::{CodeGeneratorKind, MetaclassErrorKind, SliceLiteral};
@@ -5823,7 +5823,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
&self,
expr: &PlaceExpr,
expr_ref: ast::ExprRef,
) -> (Place<'db>, Option<ScopedUseId>) {
) -> (Place<'db>, Option<FileUseId>) {
let db = self.db();
let scope = self.scope();
let file_scope_id = scope.file_scope_id(db);
@@ -5850,8 +5850,8 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
return (Place::Unbound, None);
}
let use_id = expr_ref.scoped_use_id(db, scope);
let place = place_from_bindings(db, use_def.bindings_at_use(use_id));
let use_id = expr_ref.use_id();
let place = place_from_bindings(db, use_def.bindings_for_node(use_id));
(place, Some(use_id))
}
}

View File

@@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
use ruff_python_ast::{self as ast, AnyNodeRef};
use crate::Db;
use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
use crate::node_key::ExpressionNodeKey;
use crate::semantic_index::place::ScopeId;
use crate::types::tuple::{ResizeTupleError, Tuple, TupleLength, TupleUnpacker};
use crate::types::{Type, TypeCheckDiagnostics, infer_expression_types};