diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index ef386b3585..1050446ad2 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -5876,10 +5876,12 @@ bitflags! { pub struct FunctionDecorators: u8 { /// `@classmethod` const CLASSMETHOD = 1 << 0; - /// `@no_type_check` + /// `@typing.no_type_check` const NO_TYPE_CHECK = 1 << 1; - /// `@overload` + /// `@typing.overload` const OVERLOAD = 1 << 2; + /// `@abc.abstractmethod` + const ABSTRACT_METHOD = 1 << 3; } } diff --git a/crates/red_knot_python_semantic/src/types/call/bind.rs b/crates/red_knot_python_semantic/src/types/call/bind.rs index 4a36ab726c..93217b0869 100644 --- a/crates/red_knot_python_semantic/src/types/call/bind.rs +++ b/crates/red_knot_python_semantic/src/types/call/bind.rs @@ -585,6 +585,14 @@ impl<'db> Bindings<'db> { } } + Some(KnownFunction::AbstractMethod) => { + // TODO: This can be removed once we understand legacy generics because the + // typeshed definition for `abc.abstractmethod` is an identity function. + if let [Some(ty)] = overload.parameter_types() { + overload.set_return_type(*ty); + } + } + Some(KnownFunction::GetattrStatic) => { let [Some(instance_ty), Some(attr_name), default] = overload.parameter_types() diff --git a/crates/red_knot_python_semantic/src/types/infer.rs b/crates/red_knot_python_semantic/src/types/infer.rs index 9ca92e493e..dfbf928f83 100644 --- a/crates/red_knot_python_semantic/src/types/infer.rs +++ b/crates/red_knot_python_semantic/src/types/infer.rs @@ -1482,24 +1482,37 @@ impl<'db> TypeInferenceBuilder<'db> { for decorator in decorator_list { let decorator_ty = self.infer_decorator(decorator); - if let Type::FunctionLiteral(function) = decorator_ty { - if function.is_known(self.db(), KnownFunction::NoTypeCheck) { - // If the function is decorated with the `no_type_check` decorator, - // we need to suppress any errors that come after the decorators. - self.context.set_in_no_type_check(InNoTypeCheck::Yes); - function_decorators |= FunctionDecorators::NO_TYPE_CHECK; - continue; - } else if function.is_known(self.db(), KnownFunction::Overload) { - function_decorators |= FunctionDecorators::OVERLOAD; - continue; + match decorator_ty { + Type::FunctionLiteral(function) => { + match function.known(self.db()) { + Some(KnownFunction::NoTypeCheck) => { + // If the function is decorated with the `no_type_check` decorator, + // we need to suppress any errors that come after the decorators. + self.context.set_in_no_type_check(InNoTypeCheck::Yes); + function_decorators |= FunctionDecorators::NO_TYPE_CHECK; + continue; + } + Some(KnownFunction::Overload) => { + function_decorators |= FunctionDecorators::OVERLOAD; + continue; + } + Some(KnownFunction::AbstractMethod) => { + function_decorators |= FunctionDecorators::ABSTRACT_METHOD; + continue; + } + _ => {} + } } - } else if let Type::ClassLiteral(class) = decorator_ty { - if class.is_known(self.db(), KnownClass::Classmethod) { - function_decorators |= FunctionDecorators::CLASSMETHOD; - continue; + Type::ClassLiteral(class) => { + if class.is_known(self.db(), KnownClass::Classmethod) { + function_decorators |= FunctionDecorators::CLASSMETHOD; + continue; + } } - } else if let Type::DataclassTransformer(params) = decorator_ty { - dataclass_transformer_params = Some(params); + Type::DataclassTransformer(params) => { + dataclass_transformer_params = Some(params); + } + _ => {} } decorator_types_and_nodes.push((decorator_ty, decorator));