mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[red-knot] Reduce usage of From<Type>
implementations when working with Symbol
s (#16076)
Some checks are pending
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
Some checks are pending
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
This commit is contained in:
parent
69d86d1d69
commit
df1d430294
3 changed files with 94 additions and 77 deletions
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
types::{Type, UnionType},
|
types::{todo_type, Type, UnionType},
|
||||||
Db,
|
Db,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,6 +33,17 @@ pub(crate) enum Symbol<'db> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> Symbol<'db> {
|
impl<'db> Symbol<'db> {
|
||||||
|
/// Constructor that creates a `Symbol` with boundness [`Boundness::Bound`].
|
||||||
|
pub(crate) fn bound(ty: impl Into<Type<'db>>) -> Self {
|
||||||
|
Symbol::Type(ty.into(), Boundness::Bound)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructor that creates a [`Symbol`] with a [`crate::types::TodoType`] type
|
||||||
|
/// and boundness [`Boundness::Bound`].
|
||||||
|
pub(crate) fn todo(message: &'static str) -> Self {
|
||||||
|
Symbol::Type(todo_type!(message), Boundness::Bound)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn is_unbound(&self) -> bool {
|
pub(crate) fn is_unbound(&self) -> bool {
|
||||||
matches!(self, Symbol::Unbound)
|
matches!(self, Symbol::Unbound)
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
|
||||||
}
|
}
|
||||||
// Symbol is possibly undeclared and (possibly) bound
|
// Symbol is possibly undeclared and (possibly) bound
|
||||||
Symbol::Type(inferred_ty, boundness) => Symbol::Type(
|
Symbol::Type(inferred_ty, boundness) => Symbol::Type(
|
||||||
UnionType::from_elements(db, [inferred_ty, declared_ty].iter().copied()),
|
UnionType::from_elements(db, [inferred_ty, declared_ty]),
|
||||||
boundness,
|
boundness,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
|
||||||
Err((declared_ty, _)) => {
|
Err((declared_ty, _)) => {
|
||||||
// Intentionally ignore conflicting declared types; that's not our problem,
|
// Intentionally ignore conflicting declared types; that's not our problem,
|
||||||
// it's the problem of the module we are importing from.
|
// it's the problem of the module we are importing from.
|
||||||
declared_ty.inner_type().into()
|
Symbol::bound(declared_ty.inner_type())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
|
||||||
&& file_to_module(db, scope.file(db))
|
&& file_to_module(db, scope.file(db))
|
||||||
.is_some_and(|module| module.is_known(KnownModule::Typing))
|
.is_some_and(|module| module.is_known(KnownModule::Typing))
|
||||||
{
|
{
|
||||||
return Symbol::Type(Type::BooleanLiteral(true), Boundness::Bound);
|
return Symbol::bound(Type::BooleanLiteral(true));
|
||||||
}
|
}
|
||||||
if name == "platform"
|
if name == "platform"
|
||||||
&& file_to_module(db, scope.file(db))
|
&& file_to_module(db, scope.file(db))
|
||||||
|
@ -195,10 +195,7 @@ fn symbol<'db>(db: &'db dyn Db, scope: ScopeId<'db>, name: &str) -> Symbol<'db>
|
||||||
{
|
{
|
||||||
match Program::get(db).python_platform(db) {
|
match Program::get(db).python_platform(db) {
|
||||||
crate::PythonPlatform::Identifier(platform) => {
|
crate::PythonPlatform::Identifier(platform) => {
|
||||||
return Symbol::Type(
|
return Symbol::bound(Type::string_literal(db, platform.as_str()));
|
||||||
Type::StringLiteral(StringLiteralType::new(db, platform.as_str())),
|
|
||||||
Boundness::Bound,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
crate::PythonPlatform::All => {
|
crate::PythonPlatform::All => {
|
||||||
// Fall through to the looked up type
|
// Fall through to the looked up type
|
||||||
|
@ -401,9 +398,16 @@ fn symbol_from_bindings<'db>(
|
||||||
/// If we look up the declared type of `variable` in the scope of class `C`, we will get
|
/// If we look up the declared type of `variable` in the scope of class `C`, we will get
|
||||||
/// the type `int`, a "declaredness" of [`Boundness::PossiblyUnbound`], and the information
|
/// the type `int`, a "declaredness" of [`Boundness::PossiblyUnbound`], and the information
|
||||||
/// that this comes with a [`TypeQualifiers::CLASS_VAR`] type qualifier.
|
/// that this comes with a [`TypeQualifiers::CLASS_VAR`] type qualifier.
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) struct SymbolAndQualifiers<'db>(Symbol<'db>, TypeQualifiers);
|
pub(crate) struct SymbolAndQualifiers<'db>(Symbol<'db>, TypeQualifiers);
|
||||||
|
|
||||||
impl SymbolAndQualifiers<'_> {
|
impl SymbolAndQualifiers<'_> {
|
||||||
|
/// Constructor that creates a [`SymbolAndQualifiers`] instance with a [`TodoType`] type
|
||||||
|
/// and no qualifiers.
|
||||||
|
fn todo(message: &'static str) -> Self {
|
||||||
|
Self(Symbol::todo(message), TypeQualifiers::empty())
|
||||||
|
}
|
||||||
|
|
||||||
fn is_class_var(&self) -> bool {
|
fn is_class_var(&self) -> bool {
|
||||||
self.1.contains(TypeQualifiers::CLASS_VAR)
|
self.1.contains(TypeQualifiers::CLASS_VAR)
|
||||||
}
|
}
|
||||||
|
@ -419,12 +423,6 @@ impl<'db> From<Symbol<'db>> for SymbolAndQualifiers<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> From<Type<'db>> for SymbolAndQualifiers<'db> {
|
|
||||||
fn from(ty: Type<'db>) -> Self {
|
|
||||||
SymbolAndQualifiers(ty.into(), TypeQualifiers::empty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The result of looking up a declared type from declarations; see [`symbol_from_declarations`].
|
/// The result of looking up a declared type from declarations; see [`symbol_from_declarations`].
|
||||||
type SymbolFromDeclarationsResult<'db> =
|
type SymbolFromDeclarationsResult<'db> =
|
||||||
Result<SymbolAndQualifiers<'db>, (TypeAndQualifiers<'db>, Box<[Type<'db>]>)>;
|
Result<SymbolAndQualifiers<'db>, (TypeAndQualifiers<'db>, Box<[Type<'db>]>)>;
|
||||||
|
@ -560,6 +558,11 @@ macro_rules! todo_type {
|
||||||
$crate::types::TodoType::Message($message),
|
$crate::types::TodoType::Message($message),
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
($message:ident) => {
|
||||||
|
$crate::types::Type::Dynamic($crate::types::DynamicType::Todo(
|
||||||
|
$crate::types::TodoType::Message($message),
|
||||||
|
))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
|
@ -570,6 +573,9 @@ macro_rules! todo_type {
|
||||||
($message:literal) => {
|
($message:literal) => {
|
||||||
$crate::types::Type::Dynamic($crate::types::DynamicType::Todo(crate::types::TodoType))
|
$crate::types::Type::Dynamic($crate::types::DynamicType::Todo(crate::types::TodoType))
|
||||||
};
|
};
|
||||||
|
($message:ident) => {
|
||||||
|
$crate::types::Type::Dynamic($crate::types::DynamicType::Todo(crate::types::TodoType))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) use todo_type;
|
pub(crate) use todo_type;
|
||||||
|
@ -1688,17 +1694,17 @@ impl<'db> Type<'db> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn member(&self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
|
pub(crate) fn member(&self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
|
||||||
if name == "__class__" {
|
if name == "__class__" {
|
||||||
return self.to_meta_type(db).into();
|
return Symbol::bound(self.to_meta_type(db));
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Type::Dynamic(_) => self.into(),
|
Type::Dynamic(_) => Symbol::bound(self),
|
||||||
|
|
||||||
Type::Never => todo_type!("attribute lookup on Never").into(),
|
Type::Never => Symbol::todo("attribute lookup on Never"),
|
||||||
|
|
||||||
Type::FunctionLiteral(_) => match name {
|
Type::FunctionLiteral(_) => match name {
|
||||||
"__get__" => todo_type!("`__get__` method on functions").into(),
|
"__get__" => Symbol::todo("`__get__` method on functions"),
|
||||||
"__call__" => todo_type!("`__call__` method on functions").into(),
|
"__call__" => Symbol::todo("`__call__` method on functions"),
|
||||||
_ => KnownClass::FunctionType.to_instance(db).member(db, name),
|
_ => KnownClass::FunctionType.to_instance(db).member(db, name),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1711,12 +1717,12 @@ impl<'db> Type<'db> {
|
||||||
Type::KnownInstance(known_instance) => known_instance.member(db, name),
|
Type::KnownInstance(known_instance) => known_instance.member(db, name),
|
||||||
|
|
||||||
Type::Instance(InstanceType { class }) => match (class.known(db), name) {
|
Type::Instance(InstanceType { class }) => match (class.known(db), name) {
|
||||||
(Some(KnownClass::VersionInfo), "major") => {
|
(Some(KnownClass::VersionInfo), "major") => Symbol::bound(Type::IntLiteral(
|
||||||
Type::IntLiteral(Program::get(db).python_version(db).major.into()).into()
|
Program::get(db).python_version(db).major.into(),
|
||||||
}
|
)),
|
||||||
(Some(KnownClass::VersionInfo), "minor") => {
|
(Some(KnownClass::VersionInfo), "minor") => Symbol::bound(Type::IntLiteral(
|
||||||
Type::IntLiteral(Program::get(db).python_version(db).minor.into()).into()
|
Program::get(db).python_version(db).minor.into(),
|
||||||
}
|
)),
|
||||||
_ => {
|
_ => {
|
||||||
let SymbolAndQualifiers(symbol, _) = class.instance_member(db, name);
|
let SymbolAndQualifiers(symbol, _) = class.instance_member(db, name);
|
||||||
symbol
|
symbol
|
||||||
|
@ -1762,30 +1768,30 @@ impl<'db> Type<'db> {
|
||||||
Type::Intersection(_) => {
|
Type::Intersection(_) => {
|
||||||
// TODO perform the get_member on each type in the intersection
|
// TODO perform the get_member on each type in the intersection
|
||||||
// TODO return the intersection of those results
|
// TODO return the intersection of those results
|
||||||
todo_type!("Attribute access on `Intersection` types").into()
|
Symbol::todo("Attribute access on `Intersection` types")
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::IntLiteral(_) => match name {
|
Type::IntLiteral(_) => match name {
|
||||||
"real" | "numerator" => self.into(),
|
"real" | "numerator" => Symbol::bound(self),
|
||||||
// TODO more attributes could probably be usefully special-cased
|
// TODO more attributes could probably be usefully special-cased
|
||||||
_ => KnownClass::Int.to_instance(db).member(db, name),
|
_ => KnownClass::Int.to_instance(db).member(db, name),
|
||||||
},
|
},
|
||||||
|
|
||||||
Type::BooleanLiteral(bool_value) => match name {
|
Type::BooleanLiteral(bool_value) => match name {
|
||||||
"real" | "numerator" => Type::IntLiteral(i64::from(*bool_value)).into(),
|
"real" | "numerator" => Symbol::bound(Type::IntLiteral(i64::from(*bool_value))),
|
||||||
_ => KnownClass::Bool.to_instance(db).member(db, name),
|
_ => KnownClass::Bool.to_instance(db).member(db, name),
|
||||||
},
|
},
|
||||||
|
|
||||||
Type::StringLiteral(_) => {
|
Type::StringLiteral(_) => {
|
||||||
// TODO defer to `typing.LiteralString`/`builtins.str` methods
|
// TODO defer to `typing.LiteralString`/`builtins.str` methods
|
||||||
// from typeshed's stubs
|
// from typeshed's stubs
|
||||||
todo_type!("Attribute access on `StringLiteral` types").into()
|
Symbol::todo("Attribute access on `StringLiteral` types")
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::LiteralString => {
|
Type::LiteralString => {
|
||||||
// TODO defer to `typing.LiteralString`/`builtins.str` methods
|
// TODO defer to `typing.LiteralString`/`builtins.str` methods
|
||||||
// from typeshed's stubs
|
// from typeshed's stubs
|
||||||
todo_type!("Attribute access on `LiteralString` types").into()
|
Symbol::todo("Attribute access on `LiteralString` types")
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::BytesLiteral(_) => KnownClass::Bytes.to_instance(db).member(db, name),
|
Type::BytesLiteral(_) => KnownClass::Bytes.to_instance(db).member(db, name),
|
||||||
|
@ -1797,13 +1803,13 @@ impl<'db> Type<'db> {
|
||||||
|
|
||||||
Type::Tuple(_) => {
|
Type::Tuple(_) => {
|
||||||
// TODO: implement tuple methods
|
// TODO: implement tuple methods
|
||||||
todo_type!("Attribute access on heterogeneous tuple types").into()
|
Symbol::todo("Attribute access on heterogeneous tuple types")
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::AlwaysTruthy | Type::AlwaysFalsy => match name {
|
Type::AlwaysTruthy | Type::AlwaysFalsy => match name {
|
||||||
"__bool__" => {
|
"__bool__" => {
|
||||||
// TODO should be `Callable[[], Literal[True/False]]`
|
// TODO should be `Callable[[], Literal[True/False]]`
|
||||||
todo_type!("`__bool__` for `AlwaysTruthy`/`AlwaysFalsy` Type variants").into()
|
Symbol::todo("`__bool__` for `AlwaysTruthy`/`AlwaysFalsy` Type variants")
|
||||||
}
|
}
|
||||||
_ => Type::object(db).member(db, name),
|
_ => Type::object(db).member(db, name),
|
||||||
},
|
},
|
||||||
|
@ -2528,18 +2534,6 @@ impl<'db> From<&Type<'db>> for Type<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db> From<Type<'db>> for Symbol<'db> {
|
|
||||||
fn from(value: Type<'db>) -> Self {
|
|
||||||
Symbol::Type(value, Boundness::Bound)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'db> From<&Type<'db>> for Symbol<'db> {
|
|
||||||
fn from(value: &Type<'db>) -> Self {
|
|
||||||
Self::from(*value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
pub enum DynamicType {
|
pub enum DynamicType {
|
||||||
// An explicitly annotated `typing.Any`
|
// An explicitly annotated `typing.Any`
|
||||||
|
@ -2572,7 +2566,7 @@ impl std::fmt::Display for DynamicType {
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Type qualifiers that appear in an annotation expression.
|
/// Type qualifiers that appear in an annotation expression.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||||
pub(crate) struct TypeQualifiers: u8 {
|
pub(crate) struct TypeQualifiers: u8 {
|
||||||
/// `typing.ClassVar`
|
/// `typing.ClassVar`
|
||||||
const CLASS_VAR = 1 << 0;
|
const CLASS_VAR = 1 << 0;
|
||||||
|
@ -2599,6 +2593,14 @@ impl<'db> TypeAndQualifiers<'db> {
|
||||||
Self { inner, qualifiers }
|
Self { inner, qualifiers }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructor that creates a [`TypeAndQualifiers`] instance with type `Unknown` and no qualifiers.
|
||||||
|
pub(crate) fn unknown() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Type::unknown(),
|
||||||
|
qualifiers: TypeQualifiers::empty(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Forget about type qualifiers and only return the inner type.
|
/// Forget about type qualifiers and only return the inner type.
|
||||||
pub(crate) fn inner_type(&self) -> Type<'db> {
|
pub(crate) fn inner_type(&self) -> Type<'db> {
|
||||||
self.inner
|
self.inner
|
||||||
|
@ -3330,7 +3332,7 @@ impl<'db> KnownInstanceType<'db> {
|
||||||
(Self::TypeAliasType(alias), "__name__") => Type::string_literal(db, alias.name(db)),
|
(Self::TypeAliasType(alias), "__name__") => Type::string_literal(db, alias.name(db)),
|
||||||
_ => return self.instance_fallback(db).member(db, name),
|
_ => return self.instance_fallback(db).member(db, name),
|
||||||
};
|
};
|
||||||
ty.into()
|
Symbol::bound(ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3788,8 +3790,7 @@ impl<'db> ModuleLiteralType<'db> {
|
||||||
full_submodule_name.extend(&submodule_name);
|
full_submodule_name.extend(&submodule_name);
|
||||||
if imported_submodules.contains(&full_submodule_name) {
|
if imported_submodules.contains(&full_submodule_name) {
|
||||||
if let Some(submodule) = resolve_module(db, &full_submodule_name) {
|
if let Some(submodule) = resolve_module(db, &full_submodule_name) {
|
||||||
let submodule_ty = Type::module_literal(db, importing_file, submodule);
|
return Symbol::bound(Type::module_literal(db, importing_file, submodule));
|
||||||
return Symbol::Type(submodule_ty, Boundness::Bound);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4123,7 +4124,7 @@ impl<'db> Class<'db> {
|
||||||
pub(crate) fn class_member(self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
|
pub(crate) fn class_member(self, db: &'db dyn Db, name: &str) -> Symbol<'db> {
|
||||||
if name == "__mro__" {
|
if name == "__mro__" {
|
||||||
let tuple_elements = self.iter_mro(db).map(Type::from);
|
let tuple_elements = self.iter_mro(db).map(Type::from);
|
||||||
return TupleType::from_elements(db, tuple_elements).into();
|
return Symbol::bound(TupleType::from_elements(db, tuple_elements));
|
||||||
}
|
}
|
||||||
|
|
||||||
for superclass in self.iter_mro(db) {
|
for superclass in self.iter_mro(db) {
|
||||||
|
@ -4163,7 +4164,9 @@ impl<'db> Class<'db> {
|
||||||
for superclass in self.iter_mro(db) {
|
for superclass in self.iter_mro(db) {
|
||||||
match superclass {
|
match superclass {
|
||||||
ClassBase::Dynamic(_) => {
|
ClassBase::Dynamic(_) => {
|
||||||
return todo_type!("instance attribute on class with dynamic base").into();
|
return SymbolAndQualifiers::todo(
|
||||||
|
"instance attribute on class with dynamic base",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
ClassBase::Class(class) => {
|
ClassBase::Class(class) => {
|
||||||
if let member @ SymbolAndQualifiers(Symbol::Type(_, _), _) =
|
if let member @ SymbolAndQualifiers(Symbol::Type(_, _), _) =
|
||||||
|
@ -4213,7 +4216,7 @@ impl<'db> Class<'db> {
|
||||||
.and_then(|assignments| assignments.get(name))
|
.and_then(|assignments| assignments.get(name))
|
||||||
else {
|
else {
|
||||||
if inferred_type_from_class_body.is_some() {
|
if inferred_type_from_class_body.is_some() {
|
||||||
return union_of_inferred_types.build().into();
|
return Symbol::bound(union_of_inferred_types.build());
|
||||||
}
|
}
|
||||||
return Symbol::Unbound;
|
return Symbol::Unbound;
|
||||||
};
|
};
|
||||||
|
@ -4230,7 +4233,7 @@ impl<'db> Class<'db> {
|
||||||
let annotation_ty = infer_expression_type(db, *annotation);
|
let annotation_ty = infer_expression_type(db, *annotation);
|
||||||
|
|
||||||
// TODO: check if there are conflicting declarations
|
// TODO: check if there are conflicting declarations
|
||||||
return annotation_ty.into();
|
return Symbol::bound(annotation_ty);
|
||||||
}
|
}
|
||||||
AttributeAssignment::Unannotated { value } => {
|
AttributeAssignment::Unannotated { value } => {
|
||||||
// We found an un-annotated attribute assignment of the form:
|
// We found an un-annotated attribute assignment of the form:
|
||||||
|
@ -4270,7 +4273,7 @@ impl<'db> Class<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
union_of_inferred_types.build().into()
|
Symbol::bound(union_of_inferred_types.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A helper function for `instance_member` that looks up the `name` attribute only on
|
/// A helper function for `instance_member` that looks up the `name` attribute only on
|
||||||
|
@ -4299,12 +4302,12 @@ impl<'db> Class<'db> {
|
||||||
// just a temporary heuristic to provide a broad categorization into properties
|
// just a temporary heuristic to provide a broad categorization into properties
|
||||||
// and non-property methods.
|
// and non-property methods.
|
||||||
if function.has_decorator(db, KnownClass::Property.to_class_literal(db)) {
|
if function.has_decorator(db, KnownClass::Property.to_class_literal(db)) {
|
||||||
todo_type!("@property").into()
|
SymbolAndQualifiers::todo("@property")
|
||||||
} else {
|
} else {
|
||||||
todo_type!("bound method").into()
|
SymbolAndQualifiers::todo("bound method")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SymbolAndQualifiers(Symbol::Type(declared_ty, Boundness::Bound), qualifiers)
|
SymbolAndQualifiers(Symbol::bound(declared_ty), qualifiers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(SymbolAndQualifiers(Symbol::Unbound, _)) => {
|
Ok(SymbolAndQualifiers(Symbol::Unbound, _)) => {
|
||||||
|
@ -4319,7 +4322,10 @@ impl<'db> Class<'db> {
|
||||||
}
|
}
|
||||||
Err((declared_ty, _conflicting_declarations)) => {
|
Err((declared_ty, _conflicting_declarations)) => {
|
||||||
// There are conflicting declarations for this attribute in the class body.
|
// There are conflicting declarations for this attribute in the class body.
|
||||||
SymbolAndQualifiers(declared_ty.inner_type().into(), declared_ty.qualifiers())
|
SymbolAndQualifiers(
|
||||||
|
Symbol::bound(declared_ty.inner_type()),
|
||||||
|
declared_ty.qualifiers(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -116,7 +116,9 @@ fn infer_definition_types_cycle_recovery<'db>(
|
||||||
let mut inference = TypeInference::empty(input.scope(db));
|
let mut inference = TypeInference::empty(input.scope(db));
|
||||||
let category = input.category(db);
|
let category = input.category(db);
|
||||||
if category.is_declaration() {
|
if category.is_declaration() {
|
||||||
inference.declarations.insert(input, Type::unknown().into());
|
inference
|
||||||
|
.declarations
|
||||||
|
.insert(input, TypeAndQualifiers::unknown());
|
||||||
}
|
}
|
||||||
if category.is_binding() {
|
if category.is_binding() {
|
||||||
inference.bindings.insert(input, Type::unknown());
|
inference.bindings.insert(input, Type::unknown());
|
||||||
|
@ -919,7 +921,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
inferred_ty.display(self.db())
|
inferred_ty.display(self.db())
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
Type::unknown().into()
|
TypeAndQualifiers::unknown()
|
||||||
};
|
};
|
||||||
self.types.declarations.insert(declaration, ty);
|
self.types.declarations.insert(declaration, ty);
|
||||||
}
|
}
|
||||||
|
@ -3439,8 +3441,8 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
|
|
||||||
let value_ty = self.infer_expression(value);
|
let value_ty = self.infer_expression(value);
|
||||||
match value_ty.member(self.db(), &attr.id) {
|
match value_ty.member(self.db(), &attr.id) {
|
||||||
Symbol::Type(member_ty, boundness) => {
|
Symbol::Type(member_ty, Boundness::Bound) => member_ty,
|
||||||
if boundness == Boundness::PossiblyUnbound {
|
Symbol::Type(member_ty, Boundness::PossiblyUnbound) => {
|
||||||
self.context.report_lint(
|
self.context.report_lint(
|
||||||
&POSSIBLY_UNBOUND_ATTRIBUTE,
|
&POSSIBLY_UNBOUND_ATTRIBUTE,
|
||||||
attribute.into(),
|
attribute.into(),
|
||||||
|
@ -3450,8 +3452,6 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
value_ty.display(self.db()),
|
value_ty.display(self.db()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
member_ty
|
member_ty
|
||||||
}
|
}
|
||||||
Symbol::Unbound => {
|
Symbol::Unbound => {
|
||||||
|
@ -4845,7 +4845,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
bytes.into(),
|
bytes.into(),
|
||||||
format_args!("Type expressions cannot use bytes literal"),
|
format_args!("Type expressions cannot use bytes literal"),
|
||||||
);
|
);
|
||||||
Type::unknown().into()
|
TypeAndQualifiers::unknown()
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::Expr::FString(fstring) => {
|
ast::Expr::FString(fstring) => {
|
||||||
|
@ -4855,7 +4855,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
format_args!("Type expressions cannot use f-strings"),
|
format_args!("Type expressions cannot use f-strings"),
|
||||||
);
|
);
|
||||||
self.infer_fstring_expression(fstring);
|
self.infer_fstring_expression(fstring);
|
||||||
Type::unknown().into()
|
TypeAndQualifiers::unknown()
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::Expr::Name(name) => match name.ctx {
|
ast::Expr::Name(name) => match name.ctx {
|
||||||
|
@ -4876,7 +4876,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ExprContext::Invalid => Type::unknown().into(),
|
ast::ExprContext::Invalid => TypeAndQualifiers::unknown(),
|
||||||
ast::ExprContext::Store | ast::ExprContext::Del => todo_type!().into(),
|
ast::ExprContext::Store | ast::ExprContext::Del => todo_type!().into(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -4914,7 +4914,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
inner_annotation_ty
|
inner_annotation_ty
|
||||||
} else {
|
} else {
|
||||||
self.infer_type_expression(slice);
|
self.infer_type_expression(slice);
|
||||||
Type::unknown().into()
|
TypeAndQualifiers::unknown()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
report_invalid_arguments_to_annotated(
|
report_invalid_arguments_to_annotated(
|
||||||
|
@ -4983,7 +4983,7 @@ impl<'db> TypeInferenceBuilder<'db> {
|
||||||
DeferredExpressionState::InStringAnnotation,
|
DeferredExpressionState::InStringAnnotation,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
None => Type::unknown().into(),
|
None => TypeAndQualifiers::unknown(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue