diff --git a/crates/ty_python_semantic/resources/mdtest/annotations/self.md b/crates/ty_python_semantic/resources/mdtest/annotations/self.md index 55073791da..3535d65813 100644 --- a/crates/ty_python_semantic/resources/mdtest/annotations/self.md +++ b/crates/ty_python_semantic/resources/mdtest/annotations/self.md @@ -42,7 +42,6 @@ class Shape: reveal_type(Shape().nested_type()) # revealed: list[Shape] reveal_type(Shape().nested_func()) # revealed: Shape -reveal_type(Shape().implicit_self()) # revealed: Shape class Circle(Shape): def set_scale(self: Self, scale: float) -> Self: @@ -56,6 +55,37 @@ class Outer: return self ``` +## Detection of Self + +The first argument in method is assumed to have type `typing.Self`. + +```toml +[environment] +python-version = "3.11" +``` + +```py +from typing import Self + +class A: + def implicit_self(self) -> Self: + # TODO: first argument in a method should be considered as "typing.Self" + reveal_type(self) # revealed: Unknown + return self + + def foo(self) -> int: + 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 + +reveal_type(A().implicit_self()) # revealed: A +reveal_type(A.implicit_self) # revealed: def implicit_self(self) -> Self +``` + ## typing_extensions ```toml diff --git a/crates/ty_python_semantic/resources/mdtest/call/methods.md b/crates/ty_python_semantic/resources/mdtest/call/methods.md index 9185e1722e..652d73493e 100644 --- a/crates/ty_python_semantic/resources/mdtest/call/methods.md +++ b/crates/ty_python_semantic/resources/mdtest/call/methods.md @@ -69,7 +69,9 @@ reveal_type(bound_method(1)) # revealed: str When we call the function object itself, we need to pass the `instance` explicitly: ```py -C.f(1) # error: [missing-argument] +# error: [invalid-argument-type] +# error: [missing-argument] +C.f(1) reveal_type(C.f(C(), 1)) # revealed: str ``` diff --git a/crates/ty_python_semantic/src/types/display.rs b/crates/ty_python_semantic/src/types/display.rs index a54d0e92f7..cf9669f0ad 100644 --- a/crates/ty_python_semantic/src/types/display.rs +++ b/crates/ty_python_semantic/src/types/display.rs @@ -1150,11 +1150,13 @@ impl Display for DisplayParameter<'_> { if let Some(name) = self.param.display_name() { f.write_str(&name)?; if let Some(annotated_type) = self.param.annotated_type() { - write!( - f, - ": {}", - annotated_type.display_with(self.db, self.settings) - )?; + if !self.param.type_inffered() { + write!( + f, + ": {}", + annotated_type.display_with(self.db, self.settings) + )?; + } } // Default value can only be specified if `name` is given. if let Some(default_ty) = self.param.default_type() { @@ -1167,7 +1169,9 @@ impl Display for DisplayParameter<'_> { } else if let Some(ty) = self.param.annotated_type() { // This case is specifically for the `Callable` signature where name and default value // cannot be provided. - ty.display_with(self.db, self.settings).fmt(f)?; + if !self.param.type_inffered() { + ty.display_with(self.db, self.settings).fmt(f)?; + } } Ok(()) } diff --git a/crates/ty_python_semantic/src/types/signatures.rs b/crates/ty_python_semantic/src/types/signatures.rs index 0861796298..df06a663d4 100644 --- a/crates/ty_python_semantic/src/types/signatures.rs +++ b/crates/ty_python_semantic/src/types/signatures.rs @@ -17,7 +17,7 @@ use smallvec::{SmallVec, smallvec_inline}; use super::{ DynamicType, FunctionDecorators, KnownInstanceType, Type, definition_expression_type, - infer_definition_types, nearest_enclosing_class, semantic_index, + infer_definition_types, semantic_index, }; use super::{DynamicType, Type, TypeVarVariance, definition_expression_type}; use super::{DynamicType, Type, definition_expression_type}; @@ -1179,12 +1179,14 @@ impl<'db> Parameters<'db> { let function_is_method = if matches!(definition.kind(db), DefinitionKind::Function(_)) { let scope = definition.scope(db); let index = semantic_index(db, scope.file(db)); - nearest_enclosing_class(db, index, scope).is_some() + let current_scope = index.scope(scope.file_scope_id(db)); + // class_context_of_current_method(db, index, scope).is_some() + current_scope.kind().is_class() } else { false }; let classmethod = if let DefinitionKind::Function(f) = definition.kind(db) { - if f.name.id() == "__new__" { + if matches!(f.name.id().as_str(), "__new__" | "__class_getitem__") { true } else { let result = infer_definition_types(db, definition); @@ -1198,11 +1200,12 @@ impl<'db> Parameters<'db> { } else { false }; + let positional_or_keyword = args.iter().enumerate().map(|(index, arg)| { if index == 0 && function_is_method && arg.parameter.annotation().is_none() - // TODO: Handle type of cls + // TODO: Handle case when cls is not annotated && !classmethod { let implicit_annotation = Type::KnownInstance(KnownInstanceType::TypingSelf) @@ -1210,6 +1213,7 @@ impl<'db> Parameters<'db> { .unwrap(); Parameter { annotated_type: Some(implicit_annotation), + type_inffered: true, kind: ParameterKind::PositionalOrKeyword { name: arg.parameter.name.id.clone(), default_type: default_type(arg), @@ -1383,6 +1387,10 @@ pub(crate) struct Parameter<'db> { /// Annotated type of the parameter. annotated_type: Option>, + /// If the type of parameter was inferred e.g. the first argument of a method has type + /// `typing.Self`. + type_inffered: bool, + kind: ParameterKind<'db>, pub(crate) form: ParameterForm, } @@ -1391,6 +1399,7 @@ impl<'db> Parameter<'db> { pub(crate) fn positional_only(name: Option) -> Self { Self { annotated_type: None, + type_inffered: false, kind: ParameterKind::PositionalOnly { name, default_type: None, @@ -1402,6 +1411,7 @@ impl<'db> Parameter<'db> { pub(crate) fn positional_or_keyword(name: Name) -> Self { Self { annotated_type: None, + type_inffered: false, kind: ParameterKind::PositionalOrKeyword { name, default_type: None, @@ -1413,6 +1423,7 @@ impl<'db> Parameter<'db> { pub(crate) fn variadic(name: Name) -> Self { Self { annotated_type: None, + type_inffered: false, kind: ParameterKind::Variadic { name }, form: ParameterForm::Value, } @@ -1421,6 +1432,7 @@ impl<'db> Parameter<'db> { pub(crate) fn keyword_only(name: Name) -> Self { Self { annotated_type: None, + type_inffered: false, kind: ParameterKind::KeywordOnly { name, default_type: None, @@ -1432,6 +1444,7 @@ impl<'db> Parameter<'db> { pub(crate) fn keyword_variadic(name: Name) -> Self { Self { annotated_type: None, + type_inffered: false, kind: ParameterKind::KeywordVariadic { name }, form: ParameterForm::Value, } @@ -1470,6 +1483,7 @@ impl<'db> Parameter<'db> { .annotated_type .map(|ty| ty.apply_type_mapping_impl(db, type_mapping, visitor)), kind: self.kind.apply_type_mapping_impl(db, type_mapping, visitor), + type_inffered: self.type_inffered, form: self.form, } } @@ -1485,6 +1499,7 @@ impl<'db> Parameter<'db> { ) -> Self { let Parameter { annotated_type, + type_inffered, kind, form, } = self; @@ -1527,7 +1542,14 @@ impl<'db> Parameter<'db> { }; Self { +<<<<<<< HEAD annotated_type: Some(annotated_type), +||||||| parent of 63531eab6 (Don't display the implicit typing.Self type) + annotated_type, +======= + annotated_type, + type_inffered: *type_inffered, +>>>>>>> 63531eab6 (Don't display the implicit typing.Self type) kind, form: *form, } @@ -1540,12 +1562,23 @@ impl<'db> Parameter<'db> { kind: ParameterKind<'db>, ) -> Self { Self { +<<<<<<< HEAD annotated_type: parameter.annotation().map(|annotation| { definition_expression_type(db, definition, annotation).apply_type_mapping( db, &TypeMapping::MarkTypeVarsInferable(BindingContext::Definition(definition)), ) }), +||||||| parent of 63531eab6 (Don't display the implicit typing.Self type) + annotated_type: parameter + .annotation() + .map(|annotation| definition_expression_type(db, definition, annotation)), +======= + annotated_type: parameter + .annotation() + .map(|annotation| definition_expression_type(db, definition, annotation)), + type_inffered: false, +>>>>>>> 63531eab6 (Don't display the implicit typing.Self type) kind, form: ParameterForm::Value, } @@ -1602,6 +1635,11 @@ impl<'db> Parameter<'db> { &self.kind } + /// Whether the type of the parameter was inferred. + pub(crate) fn type_inffered(&self) -> bool { + self.type_inffered + } + /// Name of the parameter (if it has one). pub(crate) fn name(&self) -> Option<&ast::name::Name> { match &self.kind {