mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-29 03:02:27 +00:00
[ty] Move class_member to member module (#20837)
## Summary Move the `class_member` function to the `member` module. This allows us to move the `member` module into the `types` module and to reduce the visibility of its contents to `pub(super)`. The drawback is that we need to make `place::place_by_id` public. ## Test Plan Pure refactoring.
This commit is contained in:
parent
f715d70be1
commit
565dbf3c9d
6 changed files with 126 additions and 124 deletions
|
|
@ -34,7 +34,6 @@ mod db;
|
|||
mod dunder_all;
|
||||
pub mod lint;
|
||||
pub(crate) mod list;
|
||||
mod member;
|
||||
mod module_name;
|
||||
mod module_resolver;
|
||||
mod node_key;
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
use crate::{
|
||||
place::{Place, PlaceAndQualifiers},
|
||||
types::Type,
|
||||
};
|
||||
|
||||
/// The return type of certain member-lookup operations. Contains information
|
||||
/// about the type, type qualifiers, boundness/declaredness, and additional
|
||||
/// metadata (e.g. whether or not the member was declared)
|
||||
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(crate) struct Member<'db> {
|
||||
/// Type, qualifiers, and boundness information of this member
|
||||
pub(crate) inner: PlaceAndQualifiers<'db>,
|
||||
|
||||
/// Whether or not this member was explicitly declared (e.g. `attr: int = 1`
|
||||
/// on the class body or `self.attr: int = 1` in a class method), or if the
|
||||
/// type was inferred (e.g. `attr = 1` on the class body or `self.attr = 1`
|
||||
/// in a class method).
|
||||
pub(crate) is_declared: bool,
|
||||
}
|
||||
|
||||
impl Default for Member<'_> {
|
||||
fn default() -> Self {
|
||||
Member::inferred(PlaceAndQualifiers::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Member<'db> {
|
||||
/// Create a new [`Member`] whose type was inferred (rather than explicitly declared).
|
||||
pub(crate) fn inferred(inner: PlaceAndQualifiers<'db>) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
is_declared: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`Member`] whose type was explicitly declared (rather than inferred).
|
||||
pub(crate) fn declared(inner: PlaceAndQualifiers<'db>) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
is_declared: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`Member`] whose type was explicitly and definitively declared, i.e.
|
||||
/// there is no control flow path in which it might be possibly undeclared.
|
||||
pub(crate) fn definitely_declared(ty: Type<'db>) -> Self {
|
||||
Self::declared(Place::bound(ty).into())
|
||||
}
|
||||
|
||||
/// Represents the absence of a member.
|
||||
pub(crate) fn unbound() -> Self {
|
||||
Self::inferred(PlaceAndQualifiers::default())
|
||||
}
|
||||
|
||||
/// Returns `true` if the inner place is unbound (i.e. there is no such member).
|
||||
pub(crate) fn is_unbound(&self) -> bool {
|
||||
self.inner.place.is_unbound()
|
||||
}
|
||||
|
||||
/// Returns the inner type, unless it is definitely unbound.
|
||||
pub(crate) fn ignore_possibly_unbound(&self) -> Option<Type<'db>> {
|
||||
self.inner.place.ignore_possibly_unbound()
|
||||
}
|
||||
|
||||
/// Map a type transformation function over the type of this member.
|
||||
#[must_use]
|
||||
pub(crate) fn map_type(self, f: impl FnOnce(Type<'db>) -> Type<'db>) -> Self {
|
||||
Self {
|
||||
inner: self.inner.map_type(f),
|
||||
is_declared: self.is_declared,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
use ruff_db::files::File;
|
||||
|
||||
use crate::dunder_all::dunder_all_names;
|
||||
use crate::member::Member;
|
||||
use crate::module_resolver::{KnownModule, file_to_module};
|
||||
use crate::semantic_index::definition::{Definition, DefinitionState};
|
||||
use crate::semantic_index::place::{PlaceExprRef, ScopedPlaceId};
|
||||
|
|
@ -233,50 +232,6 @@ pub(crate) fn place<'db>(
|
|||
)
|
||||
}
|
||||
|
||||
/// Infer the public type of a class member/symbol (its type as seen from outside its scope) in the given
|
||||
/// `scope`.
|
||||
pub(crate) fn class_member<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Member<'db> {
|
||||
place_table(db, scope)
|
||||
.symbol_id(name)
|
||||
.map(|symbol_id| {
|
||||
let place_and_quals = place_by_id(
|
||||
db,
|
||||
scope,
|
||||
symbol_id.into(),
|
||||
RequiresExplicitReExport::No,
|
||||
ConsideredDefinitions::EndOfScope,
|
||||
);
|
||||
|
||||
if !place_and_quals.place.is_unbound() && !place_and_quals.is_init_var() {
|
||||
// Trust the declared type if we see a class-level declaration
|
||||
return Member::declared(place_and_quals);
|
||||
}
|
||||
|
||||
if let PlaceAndQualifiers {
|
||||
place: Place::Type(ty, _),
|
||||
qualifiers,
|
||||
} = place_and_quals
|
||||
{
|
||||
// Otherwise, we need to check if the symbol has bindings
|
||||
let use_def = use_def_map(db, scope);
|
||||
let bindings = use_def.end_of_scope_symbol_bindings(symbol_id);
|
||||
let inferred = place_from_bindings_impl(db, bindings, RequiresExplicitReExport::No);
|
||||
|
||||
// TODO: we should not need to calculate inferred type second time. This is a temporary
|
||||
// solution until the notion of Boundness and Declaredness is split. See #16036, #16264
|
||||
Member::inferred(match inferred {
|
||||
Place::Unbound => Place::Unbound.with_qualifiers(qualifiers),
|
||||
Place::Type(_, boundness) => {
|
||||
Place::Type(ty, boundness).with_qualifiers(qualifiers)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Member::unbound()
|
||||
}
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Infers the public type of an explicit module-global symbol as seen from within the same file.
|
||||
///
|
||||
/// Note that all global scopes also include various "implicit globals" such as `__name__`,
|
||||
|
|
@ -701,7 +656,7 @@ fn place_cycle_initial<'db>(
|
|||
}
|
||||
|
||||
#[salsa::tracked(cycle_fn=place_cycle_recover, cycle_initial=place_cycle_initial, heap_size=ruff_memory_usage::heap_size)]
|
||||
fn place_by_id<'db>(
|
||||
pub(crate) fn place_by_id<'db>(
|
||||
db: &'db dyn Db,
|
||||
scope: ScopeId<'db>,
|
||||
place_id: ScopedPlaceId,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ mod generics;
|
|||
pub mod ide_support;
|
||||
mod infer;
|
||||
mod instance;
|
||||
mod member;
|
||||
mod mro;
|
||||
mod narrow;
|
||||
mod protocol_class;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use super::{
|
|||
function::FunctionType, infer_expression_type, infer_unpack_types,
|
||||
};
|
||||
use crate::FxOrderMap;
|
||||
use crate::member::Member;
|
||||
use crate::module_resolver::KnownModule;
|
||||
use crate::semantic_index::definition::{Definition, DefinitionState};
|
||||
use crate::semantic_index::scope::{NodeWithScopeKind, Scope};
|
||||
|
|
@ -22,6 +21,7 @@ use crate::types::enums::enum_metadata;
|
|||
use crate::types::function::{DataclassTransformerParams, KnownFunction};
|
||||
use crate::types::generics::{GenericContext, Specialization, walk_specialization};
|
||||
use crate::types::infer::nearest_enclosing_class;
|
||||
use crate::types::member::{Member, class_member};
|
||||
use crate::types::signatures::{CallableSignature, Parameter, Parameters, Signature};
|
||||
use crate::types::tuple::{TupleSpec, TupleType};
|
||||
use crate::types::typed_dict::typed_dict_params_from_class_def;
|
||||
|
|
@ -37,8 +37,8 @@ use crate::{
|
|||
Db, FxIndexMap, FxOrderSet, Program,
|
||||
module_resolver::file_to_module,
|
||||
place::{
|
||||
Boundness, LookupError, LookupResult, Place, PlaceAndQualifiers, class_member,
|
||||
known_module_symbol, place_from_bindings, place_from_declarations,
|
||||
Boundness, LookupError, LookupResult, Place, PlaceAndQualifiers, known_module_symbol,
|
||||
place_from_bindings, place_from_declarations,
|
||||
},
|
||||
semantic_index::{
|
||||
attribute_assignments,
|
||||
|
|
@ -3272,7 +3272,7 @@ impl<'db> ClassLiteral<'db> {
|
|||
|
||||
/// A helper function for `instance_member` that looks up the `name` attribute only on
|
||||
/// this class, not on its superclasses.
|
||||
pub(crate) fn own_instance_member(self, db: &'db dyn Db, name: &str) -> Member<'db> {
|
||||
fn own_instance_member(self, db: &'db dyn Db, name: &str) -> Member<'db> {
|
||||
// TODO: There are many things that are not yet implemented here:
|
||||
// - `typing.Final`
|
||||
// - Proper diagnostics
|
||||
|
|
|
|||
120
crates/ty_python_semantic/src/types/member.rs
Normal file
120
crates/ty_python_semantic/src/types/member.rs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
use super::Type;
|
||||
use crate::Db;
|
||||
use crate::place::{
|
||||
ConsideredDefinitions, Place, PlaceAndQualifiers, RequiresExplicitReExport, place_by_id,
|
||||
place_from_bindings,
|
||||
};
|
||||
use crate::semantic_index::{place_table, scope::ScopeId, use_def_map};
|
||||
|
||||
/// The return type of certain member-lookup operations. Contains information
|
||||
/// about the type, type qualifiers, boundness/declaredness, and additional
|
||||
/// metadata (e.g. whether or not the member was declared)
|
||||
#[derive(Debug, Clone, PartialEq, Eq, salsa::Update, get_size2::GetSize)]
|
||||
pub(super) struct Member<'db> {
|
||||
/// Type, qualifiers, and boundness information of this member
|
||||
pub(super) inner: PlaceAndQualifiers<'db>,
|
||||
|
||||
/// Whether or not this member was explicitly declared (e.g. `attr: int = 1`
|
||||
/// on the class body or `self.attr: int = 1` in a class method), or if the
|
||||
/// type was inferred (e.g. `attr = 1` on the class body or `self.attr = 1`
|
||||
/// in a class method).
|
||||
pub(super) is_declared: bool,
|
||||
}
|
||||
|
||||
impl Default for Member<'_> {
|
||||
fn default() -> Self {
|
||||
Member::inferred(PlaceAndQualifiers::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Member<'db> {
|
||||
/// Create a new [`Member`] whose type was inferred (rather than explicitly declared).
|
||||
pub(super) fn inferred(inner: PlaceAndQualifiers<'db>) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
is_declared: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`Member`] whose type was explicitly declared (rather than inferred).
|
||||
pub(super) fn declared(inner: PlaceAndQualifiers<'db>) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
is_declared: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`Member`] whose type was explicitly and definitively declared, i.e.
|
||||
/// there is no control flow path in which it might be possibly undeclared.
|
||||
pub(super) fn definitely_declared(ty: Type<'db>) -> Self {
|
||||
Self::declared(Place::bound(ty).into())
|
||||
}
|
||||
|
||||
/// Represents the absence of a member.
|
||||
pub(super) fn unbound() -> Self {
|
||||
Self::inferred(PlaceAndQualifiers::default())
|
||||
}
|
||||
|
||||
/// Returns `true` if the inner place is unbound (i.e. there is no such member).
|
||||
pub(super) fn is_unbound(&self) -> bool {
|
||||
self.inner.place.is_unbound()
|
||||
}
|
||||
|
||||
/// Returns the inner type, unless it is definitely unbound.
|
||||
pub(super) fn ignore_possibly_unbound(&self) -> Option<Type<'db>> {
|
||||
self.inner.place.ignore_possibly_unbound()
|
||||
}
|
||||
|
||||
/// Map a type transformation function over the type of this member.
|
||||
#[must_use]
|
||||
pub(super) fn map_type(self, f: impl FnOnce(Type<'db>) -> Type<'db>) -> Self {
|
||||
Self {
|
||||
inner: self.inner.map_type(f),
|
||||
is_declared: self.is_declared,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Infer the public type of a class member/symbol (its type as seen from outside its scope) in the given
|
||||
/// `scope`.
|
||||
pub(super) fn class_member<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Member<'db> {
|
||||
place_table(db, scope)
|
||||
.symbol_id(name)
|
||||
.map(|symbol_id| {
|
||||
let place_and_quals = place_by_id(
|
||||
db,
|
||||
scope,
|
||||
symbol_id.into(),
|
||||
RequiresExplicitReExport::No,
|
||||
ConsideredDefinitions::EndOfScope,
|
||||
);
|
||||
|
||||
if !place_and_quals.place.is_unbound() && !place_and_quals.is_init_var() {
|
||||
// Trust the declared type if we see a class-level declaration
|
||||
return Member::declared(place_and_quals);
|
||||
}
|
||||
|
||||
if let PlaceAndQualifiers {
|
||||
place: Place::Type(ty, _),
|
||||
qualifiers,
|
||||
} = place_and_quals
|
||||
{
|
||||
// Otherwise, we need to check if the symbol has bindings
|
||||
let use_def = use_def_map(db, scope);
|
||||
let bindings = use_def.end_of_scope_symbol_bindings(symbol_id);
|
||||
let inferred = place_from_bindings(db, bindings);
|
||||
|
||||
// TODO: we should not need to calculate inferred type second time. This is a temporary
|
||||
// solution until the notion of Boundness and Declaredness is split. See #16036, #16264
|
||||
Member::inferred(match inferred {
|
||||
Place::Unbound => Place::Unbound.with_qualifiers(qualifiers),
|
||||
Place::Type(_, boundness) => {
|
||||
Place::Type(ty, boundness).with_qualifiers(qualifiers)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Member::unbound()
|
||||
}
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue