mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-10 18:32:28 +00:00
[ty] Split ScopedPlaceId
into ScopedSymbolId
and ScopedMemberId
(#19497)
This commit is contained in:
parent
f722bfa9e6
commit
b033fb6bfd
30 changed files with 2454 additions and 1647 deletions
|
@ -30,10 +30,7 @@ use crate::semantic_index::definition::{
|
|||
StarImportDefinitionNodeRef, WithItemDefinitionNodeRef,
|
||||
};
|
||||
use crate::semantic_index::expression::{Expression, ExpressionKind};
|
||||
use crate::semantic_index::place::{
|
||||
FileScopeId, NodeWithScopeKey, NodeWithScopeKind, NodeWithScopeRef, PlaceExpr,
|
||||
PlaceExprWithFlags, PlaceTableBuilder, Scope, ScopeId, ScopeKind, ScopedPlaceId,
|
||||
};
|
||||
use crate::semantic_index::place::{PlaceExpr, PlaceTableBuilder, ScopedPlaceId};
|
||||
use crate::semantic_index::predicate::{
|
||||
CallableAndCallExpr, ClassPatternKind, PatternPredicate, PatternPredicateKind, Predicate,
|
||||
PredicateNode, PredicateOrLiteral, ScopedPredicateId, StarImportPlaceholderPredicate,
|
||||
|
@ -42,10 +39,15 @@ use crate::semantic_index::re_exports::exported_names;
|
|||
use crate::semantic_index::reachability_constraints::{
|
||||
ReachabilityConstraintsBuilder, ScopedReachabilityConstraintId,
|
||||
};
|
||||
use crate::semantic_index::scope::{
|
||||
FileScopeId, NodeWithScopeKey, NodeWithScopeKind, NodeWithScopeRef,
|
||||
};
|
||||
use crate::semantic_index::scope::{Scope, ScopeId, ScopeKind, ScopeLaziness};
|
||||
use crate::semantic_index::symbol::{ScopedSymbolId, Symbol};
|
||||
use crate::semantic_index::use_def::{
|
||||
EnclosingSnapshotKey, FlowSnapshot, ScopedEnclosingSnapshotId, UseDefMapBuilder,
|
||||
};
|
||||
use crate::semantic_index::{ArcUseDefMap, ExpressionsScopeMap, ScopeLaziness, SemanticIndex};
|
||||
use crate::semantic_index::{ArcUseDefMap, ExpressionsScopeMap, SemanticIndex};
|
||||
use crate::semantic_model::HasTrackedScope;
|
||||
use crate::unpack::{Unpack, UnpackKind, UnpackPosition, UnpackValue};
|
||||
use crate::{Db, Program};
|
||||
|
@ -295,18 +297,16 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
let enclosing_scope_kind = self.scopes[enclosing_scope_id].kind();
|
||||
let enclosing_place_table = &self.place_tables[enclosing_scope_id];
|
||||
|
||||
for nested_place in self.place_tables[popped_scope_id].places() {
|
||||
for nested_place in self.place_tables[popped_scope_id].iter() {
|
||||
// Skip this place if this enclosing scope doesn't contain any bindings for it.
|
||||
// Note that even if this place is bound in the popped scope,
|
||||
// it may refer to the enclosing scope bindings
|
||||
// so we also need to snapshot the bindings of the enclosing scope.
|
||||
|
||||
let Some(enclosing_place_id) =
|
||||
enclosing_place_table.place_id_by_expr(&nested_place.expr)
|
||||
else {
|
||||
let Some(enclosing_place_id) = enclosing_place_table.place_id(nested_place) else {
|
||||
continue;
|
||||
};
|
||||
let enclosing_place = enclosing_place_table.place_expr(enclosing_place_id);
|
||||
let enclosing_place = enclosing_place_table.place(enclosing_place_id);
|
||||
|
||||
// Snapshot the state of this place that are visible at this point in this
|
||||
// enclosing scope.
|
||||
|
@ -332,11 +332,7 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
fn bound_scope(
|
||||
&self,
|
||||
enclosing_scope: FileScopeId,
|
||||
place_expr: &PlaceExpr,
|
||||
) -> Option<FileScopeId> {
|
||||
fn bound_scope(&self, enclosing_scope: FileScopeId, symbol: &Symbol) -> Option<FileScopeId> {
|
||||
self.scope_stack
|
||||
.iter()
|
||||
.rev()
|
||||
|
@ -344,12 +340,8 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
.find_map(|scope_info| {
|
||||
let scope_id = scope_info.file_scope_id;
|
||||
let place_table = &self.place_tables[scope_id];
|
||||
let place_id = place_table.place_id_by_expr(place_expr)?;
|
||||
if place_table.place_expr(place_id).is_bound() {
|
||||
Some(scope_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let place_id = place_table.symbol_id(symbol.name())?;
|
||||
place_table.place(place_id).is_bound().then_some(scope_id)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -360,13 +352,11 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
let enclosing_scope_kind = self.scopes[enclosing_scope_id].kind();
|
||||
let enclosing_place_table = &self.place_tables[enclosing_scope_id];
|
||||
|
||||
for nested_place in self.place_tables[popped_scope_id].places() {
|
||||
// We don't record lazy snapshots of attributes or subscripts, because these are difficult to track as they modify.
|
||||
// We don't record lazy snapshots of attributes or subscripts, because these are difficult to track as they modify.
|
||||
for nested_symbol in self.place_tables[popped_scope_id].symbols() {
|
||||
// For the same reason, symbols declared as nonlocal or global are not recorded.
|
||||
// Also, if the enclosing scope allows its members to be modified from elsewhere, the snapshot will not be recorded.
|
||||
if !nested_place.is_name()
|
||||
|| self.scopes[enclosing_scope_id].visibility().is_public()
|
||||
{
|
||||
if self.scopes[enclosing_scope_id].visibility().is_public() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -374,17 +364,16 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
// Note that even if this place is bound in the popped scope,
|
||||
// it may refer to the enclosing scope bindings
|
||||
// so we also need to snapshot the bindings of the enclosing scope.
|
||||
|
||||
let Some(enclosing_place_id) =
|
||||
enclosing_place_table.place_id_by_expr(&nested_place.expr)
|
||||
let Some(enclosed_symbol_id) =
|
||||
enclosing_place_table.symbol_id(nested_symbol.name())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let enclosing_place = enclosing_place_table.place_expr(enclosing_place_id);
|
||||
let enclosing_place = enclosing_place_table.symbol(enclosed_symbol_id);
|
||||
if !enclosing_place.is_bound() {
|
||||
// If the bound scope of a place can be modified from elsewhere, the snapshot will not be recorded.
|
||||
if self
|
||||
.bound_scope(enclosing_scope_id, &nested_place.expr)
|
||||
.bound_scope(enclosing_scope_id, nested_symbol)
|
||||
.is_none_or(|scope| self.scopes[scope].visibility().is_public())
|
||||
{
|
||||
continue;
|
||||
|
@ -395,14 +384,14 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
// enclosing scope (this may later be invalidated and swept away).
|
||||
let key = EnclosingSnapshotKey {
|
||||
enclosing_scope: enclosing_scope_id,
|
||||
enclosing_place: enclosing_place_id,
|
||||
enclosing_place: enclosed_symbol_id.into(),
|
||||
nested_scope: popped_scope_id,
|
||||
nested_laziness: ScopeLaziness::Lazy,
|
||||
};
|
||||
let lazy_snapshot = self.use_def_maps[enclosing_scope_id].snapshot_outer_state(
|
||||
enclosing_place_id,
|
||||
enclosed_symbol_id.into(),
|
||||
enclosing_scope_kind,
|
||||
enclosing_place,
|
||||
enclosing_place.into(),
|
||||
);
|
||||
self.enclosing_snapshots.insert(key, lazy_snapshot);
|
||||
}
|
||||
|
@ -415,7 +404,10 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
let place_table = &self.place_tables[key.enclosing_scope];
|
||||
key.nested_laziness.is_eager()
|
||||
|| key.enclosing_scope != popped_scope_id
|
||||
|| !place_table.is_place_reassigned(key.enclosing_place)
|
||||
|| !key
|
||||
.enclosing_place
|
||||
.as_symbol()
|
||||
.is_some_and(|symbol_id| place_table.symbol(symbol_id).is_reassigned())
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -423,24 +415,27 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
self.enclosing_snapshots.retain(|key, _| {
|
||||
let place_table = &self.place_tables[key.enclosing_scope];
|
||||
|
||||
let is_place_bound_and_nonlocal = || -> bool {
|
||||
let place_expr = place_table.place_expr(key.enclosing_place);
|
||||
let is_bound_and_non_local = || -> bool {
|
||||
let ScopedPlaceId::Symbol(symbol_id) = key.enclosing_place else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let symbol = place_table.symbol(symbol_id);
|
||||
self.scopes
|
||||
.iter_enumerated()
|
||||
.skip_while(|(scope_id, _)| *scope_id != key.enclosing_scope)
|
||||
.any(|(scope_id, _)| {
|
||||
let other_scope_place_table = &self.place_tables[scope_id];
|
||||
let Some(place_id) =
|
||||
other_scope_place_table.place_id_by_expr(&place_expr.expr)
|
||||
let Some(symbol_id) = other_scope_place_table.symbol_id(symbol.name())
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
let place = other_scope_place_table.place_expr(place_id);
|
||||
place.is_marked_nonlocal() && place.is_bound()
|
||||
let symbol = other_scope_place_table.symbol(symbol_id);
|
||||
symbol.is_nonlocal() && symbol.is_bound()
|
||||
})
|
||||
};
|
||||
|
||||
key.nested_laziness.is_eager() || !is_place_bound_and_nonlocal()
|
||||
key.nested_laziness.is_eager() || !is_bound_and_non_local()
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -515,17 +510,17 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
|
||||
/// Add a symbol to the place table and the use-def map.
|
||||
/// Return the [`ScopedPlaceId`] that uniquely identifies the symbol in both.
|
||||
fn add_symbol(&mut self, name: Name) -> ScopedPlaceId {
|
||||
let (place_id, added) = self.current_place_table_mut().add_symbol(name);
|
||||
fn add_symbol(&mut self, name: Name) -> ScopedSymbolId {
|
||||
let (symbol_id, added) = self.current_place_table_mut().add_symbol(Symbol::new(name));
|
||||
if added {
|
||||
self.current_use_def_map_mut().add_place(place_id);
|
||||
self.current_use_def_map_mut().add_place(symbol_id.into());
|
||||
}
|
||||
place_id
|
||||
symbol_id
|
||||
}
|
||||
|
||||
/// Add a place to the place table and the use-def map.
|
||||
/// Return the [`ScopedPlaceId`] that uniquely identifies the place in both.
|
||||
fn add_place(&mut self, place_expr: PlaceExprWithFlags) -> ScopedPlaceId {
|
||||
fn add_place(&mut self, place_expr: PlaceExpr) -> ScopedPlaceId {
|
||||
let (place_id, added) = self.current_place_table_mut().add_place(place_expr);
|
||||
if added {
|
||||
self.current_use_def_map_mut().add_place(place_id);
|
||||
|
@ -533,16 +528,19 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
place_id
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn mark_place_bound(&mut self, id: ScopedPlaceId) {
|
||||
self.current_place_table_mut().mark_place_bound(id);
|
||||
self.current_place_table_mut().mark_bound(id);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn mark_place_declared(&mut self, id: ScopedPlaceId) {
|
||||
self.current_place_table_mut().mark_place_declared(id);
|
||||
self.current_place_table_mut().mark_declared(id);
|
||||
}
|
||||
|
||||
fn mark_place_used(&mut self, id: ScopedPlaceId) {
|
||||
self.current_place_table_mut().mark_place_used(id);
|
||||
#[track_caller]
|
||||
fn mark_symbol_used(&mut self, id: ScopedSymbolId) {
|
||||
self.current_place_table_mut().symbol_mut(id).mark_used();
|
||||
}
|
||||
|
||||
fn add_entry_for_definition_key(&mut self, key: DefinitionNodeKey) -> &mut Definitions<'db> {
|
||||
|
@ -572,23 +570,20 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
fn delete_associated_bindings(&mut self, place: ScopedPlaceId) {
|
||||
let scope = self.current_scope();
|
||||
// Don't delete associated bindings if the scope is a class scope & place is a name (it's never visible to nested scopes)
|
||||
if self.scopes[scope].kind() == ScopeKind::Class
|
||||
&& self.place_tables[scope].place_expr(place).is_name()
|
||||
{
|
||||
if self.scopes[scope].kind() == ScopeKind::Class && place.is_symbol() {
|
||||
return;
|
||||
}
|
||||
for associated_place in self.place_tables[scope].associated_place_ids(place) {
|
||||
let is_place_name = self.place_tables[scope]
|
||||
.place_expr(associated_place)
|
||||
.is_name();
|
||||
self.use_def_maps[scope].delete_binding(associated_place, is_place_name);
|
||||
for associated_place in self.place_tables[scope]
|
||||
.associated_place_ids(place)
|
||||
.iter()
|
||||
.copied()
|
||||
{
|
||||
self.use_def_maps[scope].delete_binding(associated_place.into());
|
||||
}
|
||||
}
|
||||
|
||||
fn delete_binding(&mut self, place: ScopedPlaceId) {
|
||||
let is_place_name = self.current_place_table().place_expr(place).is_name();
|
||||
self.current_use_def_map_mut()
|
||||
.delete_binding(place, is_place_name);
|
||||
self.current_use_def_map_mut().delete_binding(place);
|
||||
}
|
||||
|
||||
/// Push a new [`Definition`] onto the list of definitions
|
||||
|
@ -637,16 +632,15 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
self.mark_place_declared(place);
|
||||
}
|
||||
|
||||
let is_place_name = self.current_place_table().place_expr(place).is_name();
|
||||
let use_def = self.current_use_def_map_mut();
|
||||
match category {
|
||||
DefinitionCategory::DeclarationAndBinding => {
|
||||
use_def.record_declaration_and_binding(place, definition, is_place_name);
|
||||
use_def.record_declaration_and_binding(place, definition);
|
||||
self.delete_associated_bindings(place);
|
||||
}
|
||||
DefinitionCategory::Declaration => use_def.record_declaration(place, definition),
|
||||
DefinitionCategory::Binding => {
|
||||
use_def.record_binding(place, definition, is_place_name);
|
||||
use_def.record_binding(place, definition);
|
||||
self.delete_associated_bindings(place);
|
||||
}
|
||||
}
|
||||
|
@ -963,8 +957,8 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
// TODO create Definition for PEP 695 typevars
|
||||
// note that the "bound" on the typevar is a totally different thing than whether
|
||||
// or not a name is "bound" by a typevar declaration; the latter is always true.
|
||||
self.mark_place_bound(symbol);
|
||||
self.mark_place_declared(symbol);
|
||||
self.mark_place_bound(symbol.into());
|
||||
self.mark_place_declared(symbol.into());
|
||||
if let Some(bounds) = bound {
|
||||
self.visit_expr(bounds);
|
||||
}
|
||||
|
@ -972,9 +966,9 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
self.visit_expr(default);
|
||||
}
|
||||
match type_param {
|
||||
ast::TypeParam::TypeVar(node) => self.add_definition(symbol, node),
|
||||
ast::TypeParam::ParamSpec(node) => self.add_definition(symbol, node),
|
||||
ast::TypeParam::TypeVarTuple(node) => self.add_definition(symbol, node),
|
||||
ast::TypeParam::TypeVar(node) => self.add_definition(symbol.into(), node),
|
||||
ast::TypeParam::ParamSpec(node) => self.add_definition(symbol.into(), node),
|
||||
ast::TypeParam::TypeVarTuple(node) => self.add_definition(symbol.into(), node),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1061,20 +1055,23 @@ impl<'db, 'ast> SemanticIndexBuilder<'db, 'ast> {
|
|||
if let Some(vararg) = parameters.vararg.as_ref() {
|
||||
let symbol = self.add_symbol(vararg.name.id().clone());
|
||||
self.add_definition(
|
||||
symbol,
|
||||
symbol.into(),
|
||||
DefinitionNodeRef::VariadicPositionalParameter(vararg),
|
||||
);
|
||||
}
|
||||
if let Some(kwarg) = parameters.kwarg.as_ref() {
|
||||
let symbol = self.add_symbol(kwarg.name.id().clone());
|
||||
self.add_definition(symbol, DefinitionNodeRef::VariadicKeywordParameter(kwarg));
|
||||
self.add_definition(
|
||||
symbol.into(),
|
||||
DefinitionNodeRef::VariadicKeywordParameter(kwarg),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn declare_parameter(&mut self, parameter: &'ast ast::ParameterWithDefault) {
|
||||
let symbol = self.add_symbol(parameter.name().id().clone());
|
||||
|
||||
let definition = self.add_definition(symbol, parameter);
|
||||
let definition = self.add_definition(symbol.into(), parameter);
|
||||
|
||||
// Insert a mapping from the inner Parameter node to the same definition. This
|
||||
// ensures that calling `HasType::inferred_type` on the inner parameter returns
|
||||
|
@ -1295,12 +1292,15 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
// used to collect all the overloaded definitions of a function. This needs to be
|
||||
// done on the `Identifier` node as opposed to `ExprName` because that's what the
|
||||
// AST uses.
|
||||
self.mark_place_used(symbol);
|
||||
self.mark_symbol_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.into(),
|
||||
use_id,
|
||||
NodeKey::from_node(name),
|
||||
);
|
||||
|
||||
self.add_definition(symbol, function_def);
|
||||
self.add_definition(symbol.into(), function_def);
|
||||
}
|
||||
ast::Stmt::ClassDef(class) => {
|
||||
for decorator in &class.decorator_list {
|
||||
|
@ -1324,7 +1324,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
|
||||
// In Python runtime semantics, a class is registered after its scope is evaluated.
|
||||
let symbol = self.add_symbol(class.name.id.clone());
|
||||
self.add_definition(symbol, class);
|
||||
self.add_definition(symbol.into(), class);
|
||||
}
|
||||
ast::Stmt::TypeAlias(type_alias) => {
|
||||
let symbol = self.add_symbol(
|
||||
|
@ -1334,7 +1334,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
.map(|name| name.id.clone())
|
||||
.unwrap_or("<unknown>".into()),
|
||||
);
|
||||
self.add_definition(symbol, type_alias);
|
||||
self.add_definition(symbol.into(), type_alias);
|
||||
self.visit_expr(&type_alias.name);
|
||||
|
||||
self.with_type_params(
|
||||
|
@ -1366,7 +1366,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
|
||||
let symbol = self.add_symbol(symbol_name);
|
||||
self.add_definition(
|
||||
symbol,
|
||||
symbol.into(),
|
||||
ImportDefinitionNodeRef {
|
||||
node,
|
||||
alias_index,
|
||||
|
@ -1438,10 +1438,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
// For more details, see the doc-comment on `StarImportPlaceholderPredicate`.
|
||||
for export in exported_names(self.db, referenced_module) {
|
||||
let symbol_id = self.add_symbol(export.clone());
|
||||
let node_ref = StarImportDefinitionNodeRef {
|
||||
node,
|
||||
place_id: symbol_id,
|
||||
};
|
||||
let node_ref = StarImportDefinitionNodeRef { node, symbol_id };
|
||||
let star_import = StarImportPlaceholderPredicate::new(
|
||||
self.db,
|
||||
self.file,
|
||||
|
@ -1451,8 +1448,9 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
|
||||
let star_import_predicate = self.add_predicate(star_import.into());
|
||||
|
||||
let pre_definition =
|
||||
self.current_use_def_map().single_place_snapshot(symbol_id);
|
||||
let pre_definition = self
|
||||
.current_use_def_map()
|
||||
.single_symbol_place_snapshot(symbol_id);
|
||||
let pre_definition_reachability =
|
||||
self.current_use_def_map().reachability;
|
||||
|
||||
|
@ -1469,7 +1467,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
);
|
||||
self.current_use_def_map_mut().reachability = definition_reachability;
|
||||
|
||||
self.push_additional_definition(symbol_id, node_ref);
|
||||
self.push_additional_definition(symbol_id.into(), node_ref);
|
||||
|
||||
self.current_use_def_map_mut()
|
||||
.record_and_negate_star_import_reachability_constraint(
|
||||
|
@ -1503,7 +1501,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
let symbol = self.add_symbol(symbol_name.clone());
|
||||
|
||||
self.add_definition(
|
||||
symbol,
|
||||
symbol.into(),
|
||||
ImportFromDefinitionNodeRef {
|
||||
node,
|
||||
alias_index,
|
||||
|
@ -1580,9 +1578,9 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
|
||||
if let ast::Expr::Name(name) = &*node.target {
|
||||
let symbol_id = self.add_symbol(name.id.clone());
|
||||
let symbol = self.current_place_table().place_expr(symbol_id);
|
||||
let symbol = self.current_place_table().symbol(symbol_id);
|
||||
// Check whether the variable has been declared global.
|
||||
if symbol.is_marked_global() {
|
||||
if symbol.is_global() {
|
||||
self.report_semantic_error(SemanticSyntaxError {
|
||||
kind: SemanticSyntaxErrorKind::AnnotatedGlobal(name.id.as_str().into()),
|
||||
range: name.range,
|
||||
|
@ -1590,7 +1588,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
});
|
||||
}
|
||||
// Check whether the variable has been declared nonlocal.
|
||||
if symbol.is_marked_nonlocal() {
|
||||
if symbol.is_nonlocal() {
|
||||
self.report_semantic_error(SemanticSyntaxError {
|
||||
kind: SemanticSyntaxErrorKind::AnnotatedNonlocal(
|
||||
name.id.as_str().into(),
|
||||
|
@ -2006,7 +2004,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
let symbol = self.add_symbol(symbol_name.id.clone());
|
||||
|
||||
self.add_definition(
|
||||
symbol,
|
||||
symbol.into(),
|
||||
DefinitionNodeRef::ExceptHandler(ExceptHandlerDefinitionNodeRef {
|
||||
handler: except_handler,
|
||||
is_star: *is_star,
|
||||
|
@ -2020,7 +2018,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
self.visit_body(handler_body);
|
||||
// The caught exception is cleared at the end of the except clause
|
||||
if let Some(symbol) = symbol {
|
||||
self.delete_binding(symbol);
|
||||
self.delete_binding(symbol.into());
|
||||
}
|
||||
// Each `except` block is mutually exclusive with all other `except` blocks.
|
||||
post_except_states.push(self.flow_snapshot());
|
||||
|
@ -2078,7 +2076,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
}) => {
|
||||
for name in names {
|
||||
let symbol_id = self.add_symbol(name.id.clone());
|
||||
let symbol = self.current_place_table().place_expr(symbol_id);
|
||||
let symbol = self.current_place_table().symbol(symbol_id);
|
||||
// Check whether the variable has already been accessed in this scope.
|
||||
if symbol.is_bound() || symbol.is_declared() || symbol.is_used() {
|
||||
self.report_semantic_error(SemanticSyntaxError {
|
||||
|
@ -2091,14 +2089,16 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
});
|
||||
}
|
||||
// Check whether the variable has also been declared nonlocal.
|
||||
if symbol.is_marked_nonlocal() {
|
||||
if symbol.is_nonlocal() {
|
||||
self.report_semantic_error(SemanticSyntaxError {
|
||||
kind: SemanticSyntaxErrorKind::NonlocalAndGlobal(name.to_string()),
|
||||
range: name.range,
|
||||
python_version: self.python_version,
|
||||
});
|
||||
}
|
||||
self.current_place_table_mut().mark_place_global(symbol_id);
|
||||
self.current_place_table_mut()
|
||||
.symbol_mut(symbol_id)
|
||||
.mark_global();
|
||||
}
|
||||
walk_stmt(self, stmt);
|
||||
}
|
||||
|
@ -2109,7 +2109,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
}) => {
|
||||
for name in names {
|
||||
let symbol_id = self.add_symbol(name.id.clone());
|
||||
let symbol = self.current_place_table().place_expr(symbol_id);
|
||||
let symbol = self.current_place_table().symbol(symbol_id);
|
||||
// Check whether the variable has already been accessed in this scope.
|
||||
if symbol.is_bound() || symbol.is_declared() || symbol.is_used() {
|
||||
self.report_semantic_error(SemanticSyntaxError {
|
||||
|
@ -2122,7 +2122,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
});
|
||||
}
|
||||
// Check whether the variable has also been declared global.
|
||||
if symbol.is_marked_global() {
|
||||
if symbol.is_global() {
|
||||
self.report_semantic_error(SemanticSyntaxError {
|
||||
kind: SemanticSyntaxErrorKind::NonlocalAndGlobal(name.to_string()),
|
||||
range: name.range,
|
||||
|
@ -2139,7 +2139,8 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
// x = 1
|
||||
// ```
|
||||
self.current_place_table_mut()
|
||||
.mark_place_nonlocal(symbol_id);
|
||||
.symbol_mut(symbol_id)
|
||||
.mark_nonlocal();
|
||||
}
|
||||
walk_stmt(self, stmt);
|
||||
}
|
||||
|
@ -2151,11 +2152,8 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
// We will check the target expressions and then delete them.
|
||||
walk_stmt(self, stmt);
|
||||
for target in targets {
|
||||
if let Ok(target) = PlaceExpr::try_from(target) {
|
||||
let is_name = target.is_name();
|
||||
let place_id = self.add_place(PlaceExprWithFlags::new(target));
|
||||
let place_table = self.current_place_table_mut();
|
||||
if is_name {
|
||||
if let Some(mut target) = PlaceExpr::try_from_expr(target) {
|
||||
if let PlaceExpr::Symbol(symbol) = &mut target {
|
||||
// `del x` behaves like an assignment in that it forces all references
|
||||
// to `x` in the current scope (including *prior* references) to refer
|
||||
// to the current scope's binding (unless `x` is declared `global` or
|
||||
|
@ -2169,9 +2167,11 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
// del x
|
||||
// foo()
|
||||
// ```
|
||||
place_table.mark_place_bound(place_id);
|
||||
symbol.mark_bound();
|
||||
symbol.mark_used();
|
||||
}
|
||||
place_table.mark_place_used(place_id);
|
||||
|
||||
let place_id = self.add_place(target);
|
||||
self.delete_binding(place_id);
|
||||
}
|
||||
}
|
||||
|
@ -2238,19 +2238,20 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
ast::Expr::Name(ast::ExprName { ctx, .. })
|
||||
| ast::Expr::Attribute(ast::ExprAttribute { ctx, .. })
|
||||
| ast::Expr::Subscript(ast::ExprSubscript { ctx, .. }) => {
|
||||
if let Ok(place_expr) = PlaceExpr::try_from(expr) {
|
||||
let mut place_expr = PlaceExprWithFlags::new(place_expr);
|
||||
if self.is_method_of_class().is_some()
|
||||
&& place_expr.is_instance_attribute_candidate()
|
||||
{
|
||||
// We specifically mark attribute assignments to the first parameter of a method,
|
||||
// i.e. typically `self` or `cls`.
|
||||
let accessed_object_refers_to_first_parameter = self
|
||||
.current_first_parameter_name
|
||||
.is_some_and(|fst| place_expr.expr.root_name() == fst);
|
||||
if let Some(mut place_expr) = PlaceExpr::try_from_expr(expr) {
|
||||
if self.is_method_of_class().is_some() {
|
||||
if let PlaceExpr::Member(member) = &mut place_expr {
|
||||
if member.is_instance_attribute_candidate() {
|
||||
// We specifically mark attribute assignments to the first parameter of a method,
|
||||
// i.e. typically `self` or `cls`.
|
||||
let accessed_object_refers_to_first_parameter = self
|
||||
.current_first_parameter_name
|
||||
.is_some_and(|first| member.symbol_name() == first);
|
||||
|
||||
if accessed_object_refers_to_first_parameter && place_expr.is_member() {
|
||||
place_expr.mark_instance_attribute();
|
||||
if accessed_object_refers_to_first_parameter {
|
||||
member.mark_instance_attribute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2267,7 +2268,9 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
let place_id = self.add_place(place_expr);
|
||||
|
||||
if is_use {
|
||||
self.mark_place_used(place_id);
|
||||
if let ScopedPlaceId::Symbol(symbol_id) = place_id {
|
||||
self.mark_symbol_used(symbol_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);
|
||||
|
@ -2561,7 +2564,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
let symbol = self.add_symbol(name.id().clone());
|
||||
let state = self.current_match_case.as_ref().unwrap();
|
||||
self.add_definition(
|
||||
symbol,
|
||||
symbol.into(),
|
||||
MatchPatternDefinitionNodeRef {
|
||||
pattern: state.pattern,
|
||||
identifier: name,
|
||||
|
@ -2582,7 +2585,7 @@ impl<'ast> Visitor<'ast> for SemanticIndexBuilder<'_, 'ast> {
|
|||
let symbol = self.add_symbol(name.id().clone());
|
||||
let state = self.current_match_case.as_ref().unwrap();
|
||||
self.add_definition(
|
||||
symbol,
|
||||
symbol.into(),
|
||||
MatchPatternDefinitionNodeRef {
|
||||
pattern: state.pattern,
|
||||
identifier: name,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue