mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-02 21:03:11 +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
|
|
@ -20,10 +20,12 @@ use crate::semantic_index::builder::SemanticIndexBuilder;
|
|||
use crate::semantic_index::definition::{Definition, DefinitionNodeKey, Definitions};
|
||||
use crate::semantic_index::expression::Expression;
|
||||
use crate::semantic_index::narrowing_constraints::ScopedNarrowingConstraint;
|
||||
use crate::semantic_index::place::{
|
||||
FileScopeId, NodeWithScopeKey, NodeWithScopeRef, PlaceExpr, PlaceTable, Scope, ScopeId,
|
||||
ScopeKind, ScopedPlaceId,
|
||||
use crate::semantic_index::place::{PlaceExprRef, PlaceTable};
|
||||
pub use crate::semantic_index::scope::FileScopeId;
|
||||
use crate::semantic_index::scope::{
|
||||
NodeWithScopeKey, NodeWithScopeRef, Scope, ScopeId, ScopeKind, ScopeLaziness,
|
||||
};
|
||||
use crate::semantic_index::symbol::ScopedSymbolId;
|
||||
use crate::semantic_index::use_def::{EnclosingSnapshotKey, ScopedEnclosingSnapshotId, UseDefMap};
|
||||
use crate::semantic_model::HasTrackedScope;
|
||||
use crate::util::get_size::untracked_arc_size;
|
||||
|
|
@ -32,11 +34,14 @@ pub mod ast_ids;
|
|||
mod builder;
|
||||
pub mod definition;
|
||||
pub mod expression;
|
||||
pub(crate) mod member;
|
||||
pub(crate) mod narrowing_constraints;
|
||||
pub mod place;
|
||||
pub(crate) mod predicate;
|
||||
mod re_exports;
|
||||
mod reachability_constraints;
|
||||
pub(crate) mod scope;
|
||||
pub(crate) mod symbol;
|
||||
mod use_def;
|
||||
|
||||
pub(crate) use self::use_def::{
|
||||
|
|
@ -44,8 +49,6 @@ pub(crate) use self::use_def::{
|
|||
DeclarationWithConstraint, DeclarationsIterator,
|
||||
};
|
||||
|
||||
type PlaceSet = hashbrown::HashTable<ScopedPlaceId>;
|
||||
|
||||
/// Returns the semantic index for `file`.
|
||||
///
|
||||
/// Prefer using [`symbol_table`] when working with symbols from a single scope.
|
||||
|
|
@ -117,10 +120,10 @@ pub(crate) fn attribute_assignments<'db, 's>(
|
|||
|
||||
attribute_scopes(db, class_body_scope).filter_map(|function_scope_id| {
|
||||
let place_table = index.place_table(function_scope_id);
|
||||
let place = place_table.place_id_by_instance_attribute_name(name)?;
|
||||
let member = place_table.member_id_by_instance_attribute_name(name)?;
|
||||
let use_def = &index.use_def_maps[function_scope_id];
|
||||
Some((
|
||||
use_def.inner.all_reachable_bindings(place),
|
||||
use_def.inner.all_reachable_member_bindings(member),
|
||||
function_scope_id,
|
||||
))
|
||||
})
|
||||
|
|
@ -141,10 +144,10 @@ pub(crate) fn attribute_declarations<'db, 's>(
|
|||
|
||||
attribute_scopes(db, class_body_scope).filter_map(|function_scope_id| {
|
||||
let place_table = index.place_table(function_scope_id);
|
||||
let place = place_table.place_id_by_instance_attribute_name(name)?;
|
||||
let member = place_table.member_id_by_instance_attribute_name(name)?;
|
||||
let use_def = &index.use_def_maps[function_scope_id];
|
||||
Some((
|
||||
use_def.inner.all_reachable_declarations(place),
|
||||
use_def.inner.all_reachable_member_declarations(member),
|
||||
function_scope_id,
|
||||
))
|
||||
})
|
||||
|
|
@ -188,38 +191,6 @@ pub(crate) fn global_scope(db: &dyn Db, file: File) -> ScopeId<'_> {
|
|||
FileScopeId::global().to_scope_id(db, file)
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, get_size2::GetSize)]
|
||||
pub(crate) enum ScopeVisibility {
|
||||
/// The scope is private (e.g. function, type alias, comprehension scope).
|
||||
Private,
|
||||
/// The scope is public (e.g. module, class scope).
|
||||
Public,
|
||||
}
|
||||
|
||||
impl ScopeVisibility {
|
||||
pub(crate) const fn is_public(self) -> bool {
|
||||
matches!(self, ScopeVisibility::Public)
|
||||
}
|
||||
|
||||
pub(crate) const fn is_private(self) -> bool {
|
||||
matches!(self, ScopeVisibility::Private)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, get_size2::GetSize)]
|
||||
pub(crate) enum ScopeLaziness {
|
||||
/// The scope is evaluated lazily (e.g. function, type alias scope).
|
||||
Lazy,
|
||||
/// The scope is evaluated eagerly (e.g. module, class, comprehension scope).
|
||||
Eager,
|
||||
}
|
||||
|
||||
impl ScopeLaziness {
|
||||
pub(crate) const fn is_eager(self) -> bool {
|
||||
matches!(self, ScopeLaziness::Eager)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum EnclosingSnapshotResult<'map, 'db> {
|
||||
FoundConstraint(ScopedNarrowingConstraint),
|
||||
FoundBindings(BindingWithConstraintsIterator<'map, 'db>),
|
||||
|
|
@ -337,22 +308,18 @@ impl<'db> SemanticIndex<'db> {
|
|||
|
||||
pub(crate) fn symbol_is_global_in_scope(
|
||||
&self,
|
||||
symbol: ScopedPlaceId,
|
||||
symbol: ScopedSymbolId,
|
||||
scope: FileScopeId,
|
||||
) -> bool {
|
||||
self.place_table(scope)
|
||||
.place_expr(symbol)
|
||||
.is_marked_global()
|
||||
self.place_table(scope).symbol(symbol).is_global()
|
||||
}
|
||||
|
||||
pub(crate) fn symbol_is_nonlocal_in_scope(
|
||||
&self,
|
||||
symbol: ScopedPlaceId,
|
||||
symbol: ScopedSymbolId,
|
||||
scope: FileScopeId,
|
||||
) -> bool {
|
||||
self.place_table(scope)
|
||||
.place_expr(symbol)
|
||||
.is_marked_nonlocal()
|
||||
self.place_table(scope).symbol(symbol).is_nonlocal()
|
||||
}
|
||||
|
||||
/// Returns the id of the parent scope.
|
||||
|
|
@ -523,7 +490,7 @@ impl<'db> SemanticIndex<'db> {
|
|||
pub(crate) fn enclosing_snapshot(
|
||||
&self,
|
||||
enclosing_scope: FileScopeId,
|
||||
expr: &PlaceExpr,
|
||||
expr: PlaceExprRef,
|
||||
nested_scope: FileScopeId,
|
||||
) -> EnclosingSnapshotResult<'_, 'db> {
|
||||
for (ancestor_scope_id, ancestor_scope) in self.ancestor_scopes(nested_scope) {
|
||||
|
|
@ -531,13 +498,13 @@ impl<'db> SemanticIndex<'db> {
|
|||
break;
|
||||
}
|
||||
if !ancestor_scope.is_eager() {
|
||||
if expr.is_name() {
|
||||
if let PlaceExprRef::Symbol(symbol) = expr {
|
||||
if let Some(place_id) =
|
||||
self.place_tables[enclosing_scope].place_id_by_expr(expr)
|
||||
self.place_tables[enclosing_scope].symbol_id(symbol.name())
|
||||
{
|
||||
let key = EnclosingSnapshotKey {
|
||||
enclosing_scope,
|
||||
enclosing_place: place_id,
|
||||
enclosing_place: place_id.into(),
|
||||
nested_scope,
|
||||
nested_laziness: ScopeLaziness::Lazy,
|
||||
};
|
||||
|
|
@ -551,7 +518,7 @@ impl<'db> SemanticIndex<'db> {
|
|||
return EnclosingSnapshotResult::NoLongerInEagerContext;
|
||||
}
|
||||
}
|
||||
let Some(place_id) = self.place_tables[enclosing_scope].place_id_by_expr(expr) else {
|
||||
let Some(place_id) = self.place_tables[enclosing_scope].place_id(expr) else {
|
||||
return EnclosingSnapshotResult::NotFound;
|
||||
};
|
||||
let key = EnclosingSnapshotKey {
|
||||
|
|
@ -595,7 +562,7 @@ impl<'db> ArcUseDefMap<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct AncestorsIter<'a> {
|
||||
pub(crate) struct AncestorsIter<'a> {
|
||||
scopes: &'a IndexSlice<FileScopeId, Scope>,
|
||||
next_id: Option<FileScopeId>,
|
||||
}
|
||||
|
|
@ -623,7 +590,7 @@ impl<'a> Iterator for AncestorsIter<'a> {
|
|||
|
||||
impl FusedIterator for AncestorsIter<'_> {}
|
||||
|
||||
pub struct VisibleAncestorsIter<'a> {
|
||||
pub(crate) struct VisibleAncestorsIter<'a> {
|
||||
inner: AncestorsIter<'a>,
|
||||
starting_scope_kind: ScopeKind,
|
||||
yielded_count: usize,
|
||||
|
|
@ -670,7 +637,7 @@ impl<'a> Iterator for VisibleAncestorsIter<'a> {
|
|||
|
||||
impl FusedIterator for VisibleAncestorsIter<'_> {}
|
||||
|
||||
pub struct DescendantsIter<'a> {
|
||||
pub(crate) struct DescendantsIter<'a> {
|
||||
next_id: FileScopeId,
|
||||
descendants: std::slice::Iter<'a, Scope>,
|
||||
}
|
||||
|
|
@ -707,7 +674,7 @@ impl FusedIterator for DescendantsIter<'_> {}
|
|||
|
||||
impl ExactSizeIterator for DescendantsIter<'_> {}
|
||||
|
||||
pub struct ChildrenIter<'a> {
|
||||
pub(crate) struct ChildrenIter<'a> {
|
||||
parent: FileScopeId,
|
||||
descendants: DescendantsIter<'a>,
|
||||
}
|
||||
|
|
@ -777,13 +744,15 @@ mod tests {
|
|||
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::place::PlaceTable;
|
||||
use crate::semantic_index::scope::{FileScopeId, Scope, ScopeKind};
|
||||
use crate::semantic_index::symbol::ScopedSymbolId;
|
||||
use crate::semantic_index::use_def::UseDefMap;
|
||||
use crate::semantic_index::{global_scope, place_table, semantic_index, use_def_map};
|
||||
|
||||
impl UseDefMap<'_> {
|
||||
fn first_public_binding(&self, symbol: ScopedPlaceId) -> Option<Definition<'_>> {
|
||||
self.end_of_scope_bindings(symbol)
|
||||
fn first_public_binding(&self, symbol: ScopedSymbolId) -> Option<Definition<'_>> {
|
||||
self.end_of_scope_symbol_bindings(symbol)
|
||||
.find_map(|constrained_binding| constrained_binding.binding.definition())
|
||||
}
|
||||
|
||||
|
|
@ -813,8 +782,8 @@ mod tests {
|
|||
|
||||
fn names(table: &PlaceTable) -> Vec<String> {
|
||||
table
|
||||
.places()
|
||||
.filter_map(|expr| Some(expr.as_name()?.to_string()))
|
||||
.symbols()
|
||||
.map(|expr| expr.name().to_string())
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
@ -852,7 +821,7 @@ mod tests {
|
|||
let global_table = place_table(&db, scope);
|
||||
|
||||
assert_eq!(names(global_table), vec!["foo"]);
|
||||
let foo = global_table.place_id_by_name("foo").unwrap();
|
||||
let foo = global_table.symbol_id("foo").unwrap();
|
||||
|
||||
let use_def = use_def_map(&db, scope);
|
||||
let binding = use_def.first_public_binding(foo).unwrap();
|
||||
|
|
@ -884,18 +853,14 @@ mod tests {
|
|||
assert_eq!(names(global_table), vec!["foo"]);
|
||||
assert!(
|
||||
global_table
|
||||
.place_by_name("foo")
|
||||
.symbol_by_name("foo")
|
||||
.is_some_and(|symbol| { symbol.is_bound() && !symbol.is_used() }),
|
||||
"symbols that are defined get the defined flag"
|
||||
);
|
||||
|
||||
let use_def = use_def_map(&db, scope);
|
||||
let binding = use_def
|
||||
.first_public_binding(
|
||||
global_table
|
||||
.place_id_by_name("foo")
|
||||
.expect("symbol to exist"),
|
||||
)
|
||||
.first_public_binding(global_table.symbol_id("foo").expect("symbol to exist"))
|
||||
.unwrap();
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::ImportFrom(_)));
|
||||
}
|
||||
|
|
@ -909,13 +874,13 @@ mod tests {
|
|||
assert_eq!(names(global_table), vec!["foo", "x"]);
|
||||
assert!(
|
||||
global_table
|
||||
.place_by_name("foo")
|
||||
.symbol_by_name("foo")
|
||||
.is_some_and(|symbol| { !symbol.is_bound() && symbol.is_used() }),
|
||||
"a symbol used but not bound in a scope should have only the used flag"
|
||||
);
|
||||
let use_def = use_def_map(&db, scope);
|
||||
let binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name("x").expect("symbol exists"))
|
||||
.first_public_binding(global_table.symbol_id("x").expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::Assignment(_)));
|
||||
}
|
||||
|
|
@ -930,7 +895,7 @@ mod tests {
|
|||
|
||||
let use_def = use_def_map(&db, scope);
|
||||
let binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name("x").unwrap())
|
||||
.first_public_binding(global_table.symbol_id("x").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(
|
||||
|
|
@ -972,7 +937,7 @@ y = 2
|
|||
|
||||
let use_def = index.use_def_map(class_scope_id);
|
||||
let binding = use_def
|
||||
.first_public_binding(class_table.place_id_by_name("x").expect("symbol exists"))
|
||||
.first_public_binding(class_table.symbol_id("x").expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::Assignment(_)));
|
||||
}
|
||||
|
|
@ -1009,7 +974,7 @@ y = 2
|
|||
|
||||
let use_def = index.use_def_map(function_scope_id);
|
||||
let binding = use_def
|
||||
.first_public_binding(function_table.place_id_by_name("x").expect("symbol exists"))
|
||||
.first_public_binding(function_table.symbol_id("x").expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::Assignment(_)));
|
||||
}
|
||||
|
|
@ -1044,31 +1009,19 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
|
|||
let use_def = index.use_def_map(function_scope_id);
|
||||
for name in ["a", "b", "c", "d"] {
|
||||
let binding = use_def
|
||||
.first_public_binding(
|
||||
function_table
|
||||
.place_id_by_name(name)
|
||||
.expect("symbol exists"),
|
||||
)
|
||||
.first_public_binding(function_table.symbol_id(name).expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::Parameter(_)));
|
||||
}
|
||||
let args_binding = use_def
|
||||
.first_public_binding(
|
||||
function_table
|
||||
.place_id_by_name("args")
|
||||
.expect("symbol exists"),
|
||||
)
|
||||
.first_public_binding(function_table.symbol_id("args").expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
args_binding.kind(&db),
|
||||
DefinitionKind::VariadicPositionalParameter(_)
|
||||
));
|
||||
let kwargs_binding = use_def
|
||||
.first_public_binding(
|
||||
function_table
|
||||
.place_id_by_name("kwargs")
|
||||
.expect("symbol exists"),
|
||||
)
|
||||
.first_public_binding(function_table.symbol_id("kwargs").expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
kwargs_binding.kind(&db),
|
||||
|
|
@ -1101,27 +1054,19 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
|
|||
let use_def = index.use_def_map(lambda_scope_id);
|
||||
for name in ["a", "b", "c", "d"] {
|
||||
let binding = use_def
|
||||
.first_public_binding(lambda_table.place_id_by_name(name).expect("symbol exists"))
|
||||
.first_public_binding(lambda_table.symbol_id(name).expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::Parameter(_)));
|
||||
}
|
||||
let args_binding = use_def
|
||||
.first_public_binding(
|
||||
lambda_table
|
||||
.place_id_by_name("args")
|
||||
.expect("symbol exists"),
|
||||
)
|
||||
.first_public_binding(lambda_table.symbol_id("args").expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
args_binding.kind(&db),
|
||||
DefinitionKind::VariadicPositionalParameter(_)
|
||||
));
|
||||
let kwargs_binding = use_def
|
||||
.first_public_binding(
|
||||
lambda_table
|
||||
.place_id_by_name("kwargs")
|
||||
.expect("symbol exists"),
|
||||
)
|
||||
.first_public_binding(lambda_table.symbol_id("kwargs").expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(
|
||||
kwargs_binding.kind(&db),
|
||||
|
|
@ -1169,7 +1114,7 @@ def f(a: str, /, b: str, c: int = 1, *args, d: int = 2, **kwargs):
|
|||
let binding = use_def
|
||||
.first_public_binding(
|
||||
comprehension_symbol_table
|
||||
.place_id_by_name(name)
|
||||
.symbol_id(name)
|
||||
.expect("symbol exists"),
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -1298,7 +1243,7 @@ with item1 as x, item2 as y:
|
|||
let use_def = index.use_def_map(FileScopeId::global());
|
||||
for name in ["x", "y"] {
|
||||
let binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name(name).expect("symbol exists"))
|
||||
.first_public_binding(global_table.symbol_id(name).expect("symbol exists"))
|
||||
.expect("Expected with item definition for {name}");
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::WithItem(_)));
|
||||
}
|
||||
|
|
@ -1321,7 +1266,7 @@ with context() as (x, y):
|
|||
let use_def = index.use_def_map(FileScopeId::global());
|
||||
for name in ["x", "y"] {
|
||||
let binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name(name).expect("symbol exists"))
|
||||
.first_public_binding(global_table.symbol_id(name).expect("symbol exists"))
|
||||
.expect("Expected with item definition for {name}");
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::WithItem(_)));
|
||||
}
|
||||
|
|
@ -1371,11 +1316,7 @@ def func():
|
|||
|
||||
let use_def = index.use_def_map(FileScopeId::global());
|
||||
let binding = use_def
|
||||
.first_public_binding(
|
||||
global_table
|
||||
.place_id_by_name("func")
|
||||
.expect("symbol exists"),
|
||||
)
|
||||
.first_public_binding(global_table.symbol_id("func").expect("symbol exists"))
|
||||
.unwrap();
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::Function(_)));
|
||||
}
|
||||
|
|
@ -1452,7 +1393,7 @@ class C[T]:
|
|||
assert_eq!(names(&ann_table), vec!["T"]);
|
||||
assert!(
|
||||
ann_table
|
||||
.place_by_name("T")
|
||||
.symbol_by_name("T")
|
||||
.is_some_and(|s| s.is_bound() && !s.is_used()),
|
||||
"type parameters are defined by the scope that introduces them"
|
||||
);
|
||||
|
|
@ -1600,7 +1541,7 @@ match subject:
|
|||
let global_scope_id = global_scope(&db, file);
|
||||
let global_table = place_table(&db, global_scope_id);
|
||||
|
||||
assert!(global_table.place_by_name("Foo").unwrap().is_used());
|
||||
assert!(global_table.symbol_by_name("Foo").unwrap().is_used());
|
||||
assert_eq!(
|
||||
names(global_table),
|
||||
vec![
|
||||
|
|
@ -1624,7 +1565,7 @@ match subject:
|
|||
("l", 1),
|
||||
] {
|
||||
let binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name(name).expect("symbol exists"))
|
||||
.first_public_binding(global_table.symbol_id(name).expect("symbol exists"))
|
||||
.expect("Expected with item definition for {name}");
|
||||
if let DefinitionKind::MatchPattern(pattern) = binding.kind(&db) {
|
||||
assert_eq!(pattern.index(), expected_index);
|
||||
|
|
@ -1654,7 +1595,7 @@ match 1:
|
|||
let use_def = use_def_map(&db, global_scope_id);
|
||||
for (name, expected_index) in [("first", 0), ("second", 0)] {
|
||||
let binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name(name).expect("symbol exists"))
|
||||
.first_public_binding(global_table.symbol_id(name).expect("symbol exists"))
|
||||
.expect("Expected with item definition for {name}");
|
||||
if let DefinitionKind::MatchPattern(pattern) = binding.kind(&db) {
|
||||
assert_eq!(pattern.index(), expected_index);
|
||||
|
|
@ -1674,7 +1615,7 @@ match 1:
|
|||
|
||||
let use_def = use_def_map(&db, scope);
|
||||
let binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name("x").unwrap())
|
||||
.first_public_binding(global_table.symbol_id("x").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::For(_)));
|
||||
|
|
@ -1690,10 +1631,10 @@ match 1:
|
|||
|
||||
let use_def = use_def_map(&db, scope);
|
||||
let x_binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name("x").unwrap())
|
||||
.first_public_binding(global_table.symbol_id("x").unwrap())
|
||||
.unwrap();
|
||||
let y_binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name("y").unwrap())
|
||||
.first_public_binding(global_table.symbol_id("y").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(x_binding.kind(&db), DefinitionKind::For(_)));
|
||||
|
|
@ -1710,7 +1651,7 @@ match 1:
|
|||
|
||||
let use_def = use_def_map(&db, scope);
|
||||
let binding = use_def
|
||||
.first_public_binding(global_table.place_id_by_name("a").unwrap())
|
||||
.first_public_binding(global_table.symbol_id("a").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert!(matches!(binding.kind(&db), DefinitionKind::For(_)));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue