From a51982bac61c78aa59e96297f6510cd2566a77d7 Mon Sep 17 00:00:00 2001 From: Glyphack Date: Fri, 5 Sep 2025 20:59:21 +0200 Subject: [PATCH] Update mdtests --- .../resources/mdtest/annotations/self.md | 43 +++++--------- .../resources/mdtest/generics/scoping.md | 7 +-- .../resources/mdtest/narrow/isinstance.md | 2 + .../resources/mdtest/protocols.md | 2 - .../src/types/signatures.rs | 58 ++++++++++--------- 5 files changed, 52 insertions(+), 60 deletions(-) diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/self.md b/crates/ty_python_semantic/resources/mdtest/annotations/self.md index da74001846..aee2a80c02 100644 --- a/crates/ty_python_semantic/resources/mdtest/annotations/self.md +++ b/crates/ty_python_semantic/resources/mdtest/annotations/self.md @@ -75,15 +75,23 @@ class A: def first_arg_is_not_self(a: int) -> int: return a return first_arg_is_not_self(1) - # TODO: Make sure cls is not considered as "typing.Self". Don't know how to test this - @classmethod - def bar(cls) -> int: - return 1 -# TODO: revealed: A -# Requires implicit in method body detection -reveal_type(A().implicit_self()) # revealed: Unknown -reveal_type(A.implicit_self) # revealed: def implicit_self(self) -> Self@implicit_self + @classmethod + def bar(cls): ... + @staticmethod + def static(x): ... + +a = A() +# TODO: Should reveal Self@implicit_self. Requires implicit self in method body(https://github.com/astral-sh/ruff/pull/18473) +reveal_type(a.implicit_self()) # revealed: Unknown +reveal_type(a.implicit_self) # revealed: bound method A.implicit_self() -> A +``` + +If the method is a class or static method then first argument is not self: + +```py +A.bar() +a.static(1) ``` ## typing_extensions @@ -253,23 +261,4 @@ reveal_type(D().instance_method) reveal_type(D.class_method) ``` -## Test - -```py -from ty_extensions import generic_context -from typing import Generic, TypeVar - -T = TypeVar("T") -U = TypeVar("U") - -class C(Generic[T]): - def method(self, u: int) -> int: - return u - - def generic_method(self, t: T, u: U) -> U: - return u - -reveal_type(generic_context(C.method)) # revealed: tuple[Self@method] -``` - [self attribute]: https://typing.python.org/en/latest/spec/generics.html#use-in-attribute-annotations diff --git a/crates/ty_python_semantic/resources/mdtest/generics/scoping.md b/crates/ty_python_semantic/resources/mdtest/generics/scoping.md index 6979f918fc..f93baa8c8a 100644 --- a/crates/ty_python_semantic/resources/mdtest/generics/scoping.md +++ b/crates/ty_python_semantic/resources/mdtest/generics/scoping.md @@ -165,10 +165,9 @@ class C[T]: return y c: C[int] = C() -reveal_type(c) # revealed: C[Unknown] -# reveal_type(c) # revealed: C[Unknown] -# TODO: Next line fails. The reason is the reveal type above -# error: 13 [invalid-argument-type] "Argument to bound method `m` is incorrect: Expected `Self@m`, found `C[Unknown]`" + +# TODO: +# error: [invalid-argument-type] "Argument to bound method `m` is incorrect: Expected `Self@m`, found `C[Unknown]`" reveal_type(c.m(1, "string")) # revealed: Literal["string"] ``` diff --git a/crates/ty_python_semantic/resources/mdtest/narrow/isinstance.md b/crates/ty_python_semantic/resources/mdtest/narrow/isinstance.md index d28d261fb1..153bc62112 100644 --- a/crates/ty_python_semantic/resources/mdtest/narrow/isinstance.md +++ b/crates/ty_python_semantic/resources/mdtest/narrow/isinstance.md @@ -357,8 +357,10 @@ class Invariant[T]: def _(x: object): if isinstance(x, Invariant): reveal_type(x) # revealed: Top[Invariant[Unknown]] + # error: [invalid-argument-type] "Argument to bound method `get` is incorrect: Expected `Self@get`, found `Top[Invariant[Unknown]]`" reveal_type(x.get()) # revealed: object # error: [invalid-argument-type] "Argument to bound method `push` is incorrect: Expected `Never`, found `Literal[42]`" + # error: [invalid-argument-type] "Argument to bound method `push` is incorrect: Expected `Self@push`, found `Top[Invariant[Unknown]]`" x.push(42) ``` diff --git a/crates/ty_python_semantic/resources/mdtest/protocols.md b/crates/ty_python_semantic/resources/mdtest/protocols.md index 190a0a57f4..1267bb27fd 100644 --- a/crates/ty_python_semantic/resources/mdtest/protocols.md +++ b/crates/ty_python_semantic/resources/mdtest/protocols.md @@ -1834,7 +1834,6 @@ class P4(Protocol): @z.setter def z(self, value: int) -> None: ... -# error: [static-assert-error] static_assert(is_equivalent_to(P1, P2)) # TODO: should pass @@ -1848,7 +1847,6 @@ differently ordered unions: class A: ... class B: ... -# error: [static-assert-error] static_assert(is_equivalent_to(A | B | P1, P2 | B | A)) # TODO: should pass diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index 609b2a5da8..dcb739e9d1 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -45,7 +45,7 @@ fn infer_method_type<'db>( return None; }; let class_scope = index.scope(class_scope_id.file_scope_id(db)); - class_scope.node().as_class(&module)?; + class_scope.node().as_class()?; let method_definition = index.expect_single_definition(func_def.node(&module)); let func_type = infer_definition_types(db, method_definition) @@ -382,8 +382,12 @@ impl<'db> Signature<'db> { is_generator: bool, has_implicitly_positional_first_parameter: bool, ) -> Self { - let parameters = - Parameters::from_parameters(db, definition, function_node.parameters.as_ref()); + let parameters = Parameters::from_parameters( + db, + definition, + function_node.parameters.as_ref(), + has_implicitly_positional_first_parameter, + ); let return_ty = function_node.returns.as_ref().map(|returns| { let plain_return_ty = definition_expression_type(db, definition, returns.as_ref()) @@ -1218,42 +1222,42 @@ impl<'db> Parameters<'db> { .map(pos_only_param), ); } - + let method_type = infer_method_type(db, definition); let is_method = method_type.is_some(); let is_classmethod = method_type.is_some_and(|f| f.is_classmethod(db)); let is_staticmethod = method_type.is_some_and(|f| f.is_staticmethod(db)); let positional_or_keyword = pos_or_keyword_iter.map(|arg| { - if is_method + if is_method && !is_staticmethod && !is_classmethod && arg.parameter.annotation().is_none() && parameters.index(arg.name().id()) == Some(0) { - let implicit_annotation = Type::SpecialForm(SpecialFormType::TypingSelf) - .in_type_expression(db, definition.scope(db), Some(definition)) - .ok(); - Parameter { - annotated_type: implicit_annotation, - synthetic_annotation: true, - kind: ParameterKind::PositionalOrKeyword { - name: arg.parameter.name.id.clone(), - default_type: default_type(arg), - }, - form: ParameterForm::Value, - } + let implicit_annotation = Type::SpecialForm(SpecialFormType::TypingSelf) + .in_type_expression(db, definition.scope(db), Some(definition)) + .ok(); + Parameter { + annotated_type: implicit_annotation, + synthetic_annotation: true, + kind: ParameterKind::PositionalOrKeyword { + name: arg.parameter.name.id.clone(), + default_type: default_type(arg), + }, + form: ParameterForm::Value, + } } else { - Parameter::from_node_and_kind( - db, - definition, - &arg.parameter, - ParameterKind::PositionalOrKeyword { - name: arg.parameter.name.id.clone(), - default_type: default_type(arg), - }, - ) - } + Parameter::from_node_and_kind( + db, + definition, + &arg.parameter, + ParameterKind::PositionalOrKeyword { + name: arg.parameter.name.id.clone(), + default_type: default_type(arg), + }, + ) + } }); let variadic = vararg.as_ref().map(|arg| {