mirror of
https://github.com/microsoft/pyright.git
synced 2024-10-26 10:55:06 +03:00
Changed code that converts types to textual representation to prepend a tilde ("~") character for the inferred type of a "self" or "cls" parameter.
This commit is contained in:
parent
91b2b76e94
commit
3fa5299614
@ -297,3 +297,29 @@ def add_one(value: _StrOrFloat) -> _StrOrFloat:
|
||||
```
|
||||
|
||||
Notice that the type of variable `sum` is reported with asterisks (`*`). This indicates that internally the type checker is tracking the type as conditional. In this particular example, it indicates that `sum` is a `str` type if the parameter `value` is a `str` but is a `float` if `value` is a `float`. By tracking these conditional types, the type checker can verify that the return type is consistent with the return type `_StrOrFloat`.
|
||||
|
||||
|
||||
### Inferred type of self and cls parameters
|
||||
|
||||
When a type annotation for a method’s `self` or `cls` parameter is omitted, pyright will infer its type based on the class that contains the method. The inferred type is internally represented as a type variable that is bound to the class.
|
||||
|
||||
Within the function, the type of `self` is printed with a tilde preceding the class name. This indicates that the type is a TypeVar bound to the class rather than the class itself. Outside of the function, this TypeVar is resolved based on the usage.
|
||||
|
||||
```python
|
||||
class Parent:
|
||||
def method1(self):
|
||||
reveal_type(self) # ~Parent
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def method2(cls):
|
||||
reveal_type(cls) # Type[~Parent]
|
||||
return cls
|
||||
|
||||
class Child(Parent):
|
||||
...
|
||||
|
||||
reveal_type(Child().method1()) # Child
|
||||
reveal_type(Child.method2()) # Type[Child]
|
||||
```
|
||||
|
||||
|
@ -53,9 +53,13 @@ export const enum PrintTypeFlags {
|
||||
// Expand type aliases to display their individual parts?
|
||||
ExpandTypeAlias = 1 << 5,
|
||||
|
||||
// Add "*" for types that are conditionally constrained when
|
||||
// Omit "*" for types that are conditionally constrained when
|
||||
// used with constrained TypeVars.
|
||||
OmitConditionalConstraint = 1 << 6,
|
||||
|
||||
// Omit "~" for synthesized type variables that represent the
|
||||
// type of an unannotated self or cls parameter.
|
||||
OmitSelfClsTypeIndicator = 1 << 7,
|
||||
}
|
||||
|
||||
export type FunctionReturnTypeCallback = (type: FunctionType) => Type;
|
||||
@ -317,14 +321,24 @@ export function printType(
|
||||
return type.details.recursiveTypeAliasName;
|
||||
}
|
||||
|
||||
// If it's a synthesized type var used to implement `self` or `cls` types,
|
||||
// print the type with a special character that indicates that the type
|
||||
// is internally represented as a TypeVar.
|
||||
if (type.details.boundType) {
|
||||
const boundTypeString = printType(
|
||||
let boundTypeString = printType(
|
||||
type.details.boundType,
|
||||
printTypeFlags & ~PrintTypeFlags.ExpandTypeAlias,
|
||||
returnTypeCallback,
|
||||
recursionTypes
|
||||
);
|
||||
|
||||
if (
|
||||
(printTypeFlags & PrintTypeFlags.OmitSelfClsTypeIndicator) === 0 &&
|
||||
!isAnyOrUnknown(type.details.boundType)
|
||||
) {
|
||||
boundTypeString = `~${boundTypeString}`;
|
||||
}
|
||||
|
||||
if (TypeBase.isInstantiable(type)) {
|
||||
return `Type[${boundTypeString}]`;
|
||||
}
|
||||
@ -549,7 +563,12 @@ export function printFunctionParts(
|
||||
const paramType = FunctionType.getEffectiveParameterType(type, index);
|
||||
const paramTypeString =
|
||||
recursionTypes.length < maxTypeRecursionCount
|
||||
? printType(paramType, printTypeFlags, returnTypeCallback, recursionTypes)
|
||||
? printType(
|
||||
paramType,
|
||||
printTypeFlags | PrintTypeFlags.OmitSelfClsTypeIndicator,
|
||||
returnTypeCallback,
|
||||
recursionTypes
|
||||
)
|
||||
: '';
|
||||
paramString += ': ' + paramTypeString;
|
||||
|
||||
|
@ -8,14 +8,14 @@ class Foo:
|
||||
@classmethod
|
||||
def bar(cls, other: type):
|
||||
if issubclass(other, cls):
|
||||
t1: Literal["Type[Foo]"] = reveal_type(other)
|
||||
t1: Literal["Type[~Foo]"] = reveal_type(other)
|
||||
|
||||
if issubclass(other, (int, cls)):
|
||||
t2: Literal["Type[Foo] | Type[int]"] = reveal_type(other)
|
||||
t2: Literal["Type[~Foo] | Type[int]"] = reveal_type(other)
|
||||
|
||||
def baz(self, other: object):
|
||||
if isinstance(other, self.__class__):
|
||||
t1: Literal["Foo"] = reveal_type(other)
|
||||
t1: Literal["~Foo"] = reveal_type(other)
|
||||
|
||||
if isinstance(other, (int, self.__class__)):
|
||||
t2: Literal["Foo | int"] = reveal_type(other)
|
||||
t2: Literal["~Foo | int"] = reveal_type(other)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# This sample tests the use of a generic property class.
|
||||
# This sample tests the use of a generic descriptor class.
|
||||
|
||||
from typing import Any, Callable, Generic, Literal, Optional, Type, TypeVar, overload
|
||||
|
||||
@ -72,4 +72,4 @@ class B:
|
||||
|
||||
b = B()
|
||||
t_b1: Literal["str"] = reveal_type(b.foo)
|
||||
t_b2: Literal["Minimal[B, str]"] = reveal_type(B.foo)
|
||||
t_b2: Literal["Minimal[~B, str]"] = reveal_type(B.foo)
|
||||
|
Loading…
Reference in New Issue
Block a user