mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 13:24:57 +00:00
[ty] Minor cleanups (#20240)
Some checks are pending
CI / mkdocs (push) Waiting to run
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
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 / Fuzz for new ty panics (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 / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / mkdocs (push) Waiting to run
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
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 / Fuzz for new ty panics (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 / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
## Summary Two minor cleanups: - Return `Option<ClassType>` rather than `Option<ClassLiteral>` from `TypeInferenceBuilder::class_context_of_current_method`. Now that `ClassType::is_protocol` exists as a method as well as `ClassLiteral::is_protocol`, this simplifies most of the call-sites of the `class_context_of_current_method()` method. - Make more use of the `MethodDecorator::try_from_fn_type` method in `class.rs`. Under the hood, this method uses the new methods `FunctionType::is_classmethod()` and `FunctionType::is_staticmethod()` that @sharkdp recently added, so it gets the semantics more precisely correct than the code it's replacing in `infer.rs` (by accounting for implicit staticmethods/classmethods as well as explicit ones). By using these methods we can delete some code elsewhere (the `FunctionDecorators::from_decorator_types()` constructor) ## Test Plan Existing tests
This commit is contained in:
parent
c6516e9b60
commit
555b9f78d6
5 changed files with 83 additions and 97 deletions
|
@ -1254,7 +1254,7 @@ pub(super) enum MethodDecorator {
|
|||
}
|
||||
|
||||
impl MethodDecorator {
|
||||
fn try_from_fn_type(db: &dyn Db, fn_type: FunctionType) -> Result<Self, ()> {
|
||||
pub(crate) fn try_from_fn_type(db: &dyn Db, fn_type: FunctionType) -> Result<Self, ()> {
|
||||
match (fn_type.is_classmethod(db), fn_type.is_staticmethod(db)) {
|
||||
(true, true) => Err(()), // A method can't be static and class method at the same time.
|
||||
(true, false) => Ok(Self::ClassMethod),
|
||||
|
|
|
@ -19,7 +19,8 @@ use crate::types::string_annotation::{
|
|||
RAW_STRING_TYPE_ANNOTATION,
|
||||
};
|
||||
use crate::types::{
|
||||
DynamicType, LintDiagnosticGuard, Protocol, ProtocolInstanceType, SubclassOfInner, binding_type,
|
||||
ClassType, DynamicType, LintDiagnosticGuard, Protocol, ProtocolInstanceType, SubclassOfInner,
|
||||
binding_type,
|
||||
};
|
||||
use crate::types::{SpecialFormType, Type, protocol_class::ProtocolClass};
|
||||
use crate::util::diagnostics::format_enumeration;
|
||||
|
@ -2088,7 +2089,7 @@ pub(super) fn report_implicit_return_type(
|
|||
range: impl Ranged,
|
||||
expected_ty: Type,
|
||||
has_empty_body: bool,
|
||||
enclosing_class_of_method: Option<ClassLiteral>,
|
||||
enclosing_class_of_method: Option<ClassType>,
|
||||
no_return: bool,
|
||||
) {
|
||||
let Some(builder) = context.report_lint(&INVALID_RETURN_TYPE, range) else {
|
||||
|
@ -2122,7 +2123,7 @@ pub(super) fn report_implicit_return_type(
|
|||
let Some(class) = enclosing_class_of_method else {
|
||||
return;
|
||||
};
|
||||
if class.iter_mro(db, None).contains(&ClassBase::Protocol) {
|
||||
if class.iter_mro(db).contains(&ClassBase::Protocol) {
|
||||
diagnostic.info(format_args!(
|
||||
"Class `{}` has `typing.Protocol` in its MRO, but it is not a protocol class",
|
||||
class.name(db)
|
||||
|
|
|
@ -142,17 +142,6 @@ impl FunctionDecorators {
|
|||
_ => FunctionDecorators::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn from_decorator_types<'db>(
|
||||
db: &'db dyn Db,
|
||||
types: impl IntoIterator<Item = Type<'db>>,
|
||||
) -> Self {
|
||||
types
|
||||
.into_iter()
|
||||
.fold(FunctionDecorators::empty(), |acc, ty| {
|
||||
acc | FunctionDecorators::from_decorator_type(db, ty)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
|
|
@ -92,7 +92,7 @@ use crate::semantic_index::{
|
|||
ApplicableConstraints, EnclosingSnapshotResult, SemanticIndex, place_table, semantic_index,
|
||||
};
|
||||
use crate::types::call::{Binding, Bindings, CallArguments, CallError, CallErrorKind};
|
||||
use crate::types::class::{CodeGeneratorKind, FieldKind, MetaclassErrorKind};
|
||||
use crate::types::class::{CodeGeneratorKind, FieldKind, MetaclassErrorKind, MethodDecorator};
|
||||
use crate::types::diagnostic::{
|
||||
self, CALL_NON_CALLABLE, CONFLICTING_DECLARATIONS, CONFLICTING_METACLASS,
|
||||
CYCLIC_CLASS_DEFINITION, DIVISION_BY_ZERO, DUPLICATE_KW_ONLY, INCONSISTENT_MRO,
|
||||
|
@ -2415,7 +2415,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
/// is a class scope OR the immediate parent scope is an annotation scope
|
||||
/// and the grandparent scope is a class scope. This means it has different
|
||||
/// behaviour to the [`nearest_enclosing_class`] function.
|
||||
fn class_context_of_current_method(&self) -> Option<ClassLiteral<'db>> {
|
||||
fn class_context_of_current_method(&self) -> Option<ClassType<'db>> {
|
||||
let current_scope_id = self.scope().file_scope_id(self.db());
|
||||
let current_scope = self.index.scope(current_scope_id);
|
||||
if current_scope.kind() != ScopeKind::Function {
|
||||
|
@ -2440,7 +2440,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
|
||||
let class_stmt = class_scope.node().as_class(self.module())?;
|
||||
let class_definition = self.index.expect_single_definition(class_stmt);
|
||||
binding_type(self.db(), class_definition).into_class_literal()
|
||||
binding_type(self.db(), class_definition).to_class_type(self.db())
|
||||
}
|
||||
|
||||
/// If the current scope is a (non-lambda) function, return that function's AST node.
|
||||
|
@ -7177,26 +7177,22 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
|||
|
||||
let first_parameter_name = first_parameter.name();
|
||||
|
||||
let function_decorators = FunctionDecorators::from_decorator_types(
|
||||
self.db(),
|
||||
self.function_decorator_types(current_function),
|
||||
);
|
||||
let function_definition = self.index.expect_single_definition(current_function);
|
||||
let Type::FunctionLiteral(function_type) = binding_type(self.db(), function_definition)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let attribute_exists = if function_decorators.contains(FunctionDecorators::CLASSMETHOD) {
|
||||
if function_decorators.contains(FunctionDecorators::STATICMETHOD) {
|
||||
return;
|
||||
}
|
||||
!Type::instance(self.db(), class.default_specialization(self.db()))
|
||||
let attribute_exists = match MethodDecorator::try_from_fn_type(self.db(), function_type) {
|
||||
Ok(MethodDecorator::ClassMethod) => !Type::instance(self.db(), class)
|
||||
.class_member(self.db(), id.clone())
|
||||
.place
|
||||
.is_unbound()
|
||||
} else if !function_decorators.contains(FunctionDecorators::STATICMETHOD) {
|
||||
!Type::instance(self.db(), class.default_specialization(self.db()))
|
||||
.is_unbound(),
|
||||
Ok(MethodDecorator::None) => !Type::instance(self.db(), class)
|
||||
.member(self.db(), id)
|
||||
.place
|
||||
.is_unbound()
|
||||
} else {
|
||||
false
|
||||
.is_unbound(),
|
||||
Ok(MethodDecorator::StaticMethod) | Err(()) => false,
|
||||
};
|
||||
|
||||
if attribute_exists {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue