Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions crates/ty_ide/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1247,7 +1247,7 @@ quux.<CURSOR>
__init_subclass__ :: bound method object.__init_subclass__() -> None
__module__ :: str
__ne__ :: bound method object.__ne__(value: object, /) -> bool
__new__ :: bound method object.__new__() -> Self
__new__ :: bound method object.__new__() -> Self@object
__reduce__ :: bound method object.__reduce__() -> str | tuple[Any, ...]
__reduce_ex__ :: bound method object.__reduce_ex__(protocol: SupportsIndex, /) -> str | tuple[Any, ...]
__repr__ :: bound method object.__repr__() -> str
Expand Down Expand Up @@ -1292,7 +1292,7 @@ quux.b<CURSOR>
__init_subclass__ :: bound method object.__init_subclass__() -> None
__module__ :: str
__ne__ :: bound method object.__ne__(value: object, /) -> bool
__new__ :: bound method object.__new__() -> Self
__new__ :: bound method object.__new__() -> Self@object
__reduce__ :: bound method object.__reduce__() -> str | tuple[Any, ...]
__reduce_ex__ :: bound method object.__reduce_ex__(protocol: SupportsIndex, /) -> str | tuple[Any, ...]
__repr__ :: bound method object.__repr__() -> str
Expand Down Expand Up @@ -1346,7 +1346,7 @@ C.<CURSOR>
__mro__ :: tuple[<class 'C'>, <class 'object'>]
__name__ :: str
__ne__ :: def __ne__(self, value: object, /) -> bool
__new__ :: def __new__(cls) -> Self
__new__ :: def __new__(cls) -> Self@object
__or__ :: bound method <class 'C'>.__or__(value: Any, /) -> UnionType
__prepare__ :: bound method <class 'Meta'>.__prepare__(name: str, bases: tuple[type, ...], /, **kwds: Any) -> MutableMapping[str, object]
__qualname__ :: str
Expand Down Expand Up @@ -1522,7 +1522,7 @@ Quux.<CURSOR>
__mro__ :: tuple[<class 'Quux'>, <class 'object'>]
__name__ :: str
__ne__ :: def __ne__(self, value: object, /) -> bool
__new__ :: def __new__(cls) -> Self
__new__ :: def __new__(cls) -> Self@object
__or__ :: bound method <class 'Quux'>.__or__(value: Any, /) -> UnionType
__prepare__ :: bound method <class 'type'>.__prepare__(name: str, bases: tuple[type, ...], /, **kwds: Any) -> MutableMapping[str, object]
__qualname__ :: str
Expand Down Expand Up @@ -1574,8 +1574,8 @@ Answer.<CURSOR>
__bool__ :: bound method <class 'Answer'>.__bool__() -> Literal[True]
__class__ :: <class 'EnumMeta'>
__contains__ :: bound method <class 'Answer'>.__contains__(value: object) -> bool
__copy__ :: def __copy__(self) -> Self
__deepcopy__ :: def __deepcopy__(self, memo: Any) -> Self
__copy__ :: def __copy__(self) -> Self@Enum
__deepcopy__ :: def __deepcopy__(self, memo: Any) -> Self@Enum
__delattr__ :: def __delattr__(self, name: str, /) -> None
__dict__ :: MappingProxyType[str, Any]
__dictoffset__ :: int
Expand All @@ -1585,28 +1585,28 @@ Answer.<CURSOR>
__flags__ :: int
__format__ :: def __format__(self, format_spec: str) -> str
__getattribute__ :: def __getattribute__(self, name: str, /) -> Any
__getitem__ :: bound method <class 'Answer'>.__getitem__(name: str) -> _EnumMemberT
__getitem__ :: bound method <class 'Answer'>.__getitem__(name: str) -> _EnumMemberT@__getitem__
__getstate__ :: def __getstate__(self) -> object
__hash__ :: def __hash__(self) -> int
__init__ :: def __init__(self) -> None
__init_subclass__ :: def __init_subclass__(cls) -> None
__instancecheck__ :: bound method <class 'Answer'>.__instancecheck__(instance: Any, /) -> bool
__itemsize__ :: int
__iter__ :: bound method <class 'Answer'>.__iter__() -> Iterator[_EnumMemberT]
__iter__ :: bound method <class 'Answer'>.__iter__() -> Iterator[_EnumMemberT@__iter__]
__len__ :: bound method <class 'Answer'>.__len__() -> int
__members__ :: MappingProxyType[str, Unknown]
__module__ :: str
__mro__ :: tuple[<class 'Answer'>, <class 'Enum'>, <class 'object'>]
__name__ :: str
__ne__ :: def __ne__(self, value: object, /) -> bool
__new__ :: def __new__(cls, value: object) -> Self
__new__ :: def __new__(cls, value: object) -> Self@Enum
__or__ :: bound method <class 'Answer'>.__or__(value: Any, /) -> UnionType
__order__ :: str
__prepare__ :: bound method <class 'EnumMeta'>.__prepare__(cls: str, bases: tuple[type, ...], **kwds: Any) -> _EnumDict
__qualname__ :: str
__reduce__ :: def __reduce__(self) -> str | tuple[Any, ...]
__repr__ :: def __repr__(self) -> str
__reversed__ :: bound method <class 'Answer'>.__reversed__() -> Iterator[_EnumMemberT]
__reversed__ :: bound method <class 'Answer'>.__reversed__() -> Iterator[_EnumMemberT@__reversed__]
__ror__ :: bound method <class 'Answer'>.__ror__(value: Any, /) -> UnionType
__setattr__ :: def __setattr__(self, name: str, value: Any, /) -> None
__signature__ :: bound method <class 'Answer'>.__signature__() -> str
Expand Down
4 changes: 2 additions & 2 deletions crates/ty_ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,10 +371,10 @@ mod tests {
);

assert_snapshot!(test.hover(), @r"
T
T@Alias
---------------------------------------------
```python
T
T@Alias
```
---------------------------------------------
info[hover]: Hovered content is
Expand Down
10 changes: 5 additions & 5 deletions crates/ty_python_semantic/resources/mdtest/annotations/self.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ from typing import Self

class Shape:
def set_scale(self: Self, scale: float) -> Self:
reveal_type(self) # revealed: Self
reveal_type(self) # revealed: Self@Shape
return self

def nested_type(self: Self) -> list[Self]:
return [self]

def nested_func(self: Self) -> Self:
def inner() -> Self:
reveal_type(self) # revealed: Self
reveal_type(self) # revealed: Self@Shape
return self
return inner()

Expand All @@ -38,13 +38,13 @@ reveal_type(Shape().nested_func()) # revealed: Shape

class Circle(Shape):
def set_scale(self: Self, scale: float) -> Self:
reveal_type(self) # revealed: Self
reveal_type(self) # revealed: Self@Circle
return self

class Outer:
class Inner:
def foo(self: Self) -> Self:
reveal_type(self) # revealed: Self
reveal_type(self) # revealed: Self@Inner
return self
```

Expand Down Expand Up @@ -151,7 +151,7 @@ from typing import Self

class Shape:
def union(self: Self, other: Self | None):
reveal_type(other) # revealed: Self | None
reveal_type(other) # revealed: Self@Shape | None
return self
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def i(callback: Callable[Concatenate[int, P], R_co], *args: P.args, **kwargs: P.

class Foo:
def method(self, x: Self):
reveal_type(x) # revealed: Self
reveal_type(x) # revealed: Self@Foo
```

## Type expressions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ S = TypeVar("S")
class SingleTypevar(Generic[T]): ...
class MultipleTypevars(Generic[T, S]): ...

reveal_type(generic_context(SingleTypevar)) # revealed: tuple[T]
reveal_type(generic_context(MultipleTypevars)) # revealed: tuple[T, S]
# revealed: tuple[T@SingleTypevar]
reveal_type(generic_context(SingleTypevar))
# revealed: tuple[T@MultipleTypevars, S@MultipleTypevars]
reveal_type(generic_context(MultipleTypevars))
```

Inheriting from `Generic` multiple times yields a `duplicate-base` diagnostic, just like any other
Expand Down Expand Up @@ -49,9 +51,12 @@ class InheritedGeneric(MultipleTypevars[T, S]): ...
class InheritedGenericPartiallySpecialized(MultipleTypevars[T, int]): ...
class InheritedGenericFullySpecialized(MultipleTypevars[str, int]): ...

reveal_type(generic_context(InheritedGeneric)) # revealed: tuple[T, S]
reveal_type(generic_context(InheritedGenericPartiallySpecialized)) # revealed: tuple[T]
reveal_type(generic_context(InheritedGenericFullySpecialized)) # revealed: None
# revealed: tuple[T@InheritedGeneric, S@InheritedGeneric]
reveal_type(generic_context(InheritedGeneric))
# revealed: tuple[T@InheritedGenericPartiallySpecialized]
reveal_type(generic_context(InheritedGenericPartiallySpecialized))
# revealed: None
reveal_type(generic_context(InheritedGenericFullySpecialized))
```

If you don't specialize a generic base class, we use the default specialization, which maps each
Expand All @@ -78,9 +83,12 @@ class ExplicitInheritedGenericPartiallySpecializedExtraTypevar(MultipleTypevars[
# error: [invalid-generic-class] "`Generic` base class must include all type variables used in other base classes"
class ExplicitInheritedGenericPartiallySpecializedMissingTypevar(MultipleTypevars[T, int], Generic[S]): ...

reveal_type(generic_context(ExplicitInheritedGeneric)) # revealed: tuple[T, S]
reveal_type(generic_context(ExplicitInheritedGenericPartiallySpecialized)) # revealed: tuple[T]
reveal_type(generic_context(ExplicitInheritedGenericPartiallySpecializedExtraTypevar)) # revealed: tuple[T, S]
# revealed: tuple[T@ExplicitInheritedGeneric, S@ExplicitInheritedGeneric]
reveal_type(generic_context(ExplicitInheritedGeneric))
# revealed: tuple[T@ExplicitInheritedGenericPartiallySpecialized]
reveal_type(generic_context(ExplicitInheritedGenericPartiallySpecialized))
# revealed: tuple[T@ExplicitInheritedGenericPartiallySpecializedExtraTypevar, S@ExplicitInheritedGenericPartiallySpecializedExtraTypevar]
reveal_type(generic_context(ExplicitInheritedGenericPartiallySpecializedExtraTypevar))
```

## Specializing generic classes explicitly
Expand Down Expand Up @@ -446,18 +454,18 @@ class C(Generic[T]):
def generic_method(self, t: T, u: U) -> U:
return u

reveal_type(generic_context(C)) # revealed: tuple[T]
reveal_type(generic_context(C)) # revealed: tuple[T@C]
reveal_type(generic_context(C.method)) # revealed: None
reveal_type(generic_context(C.generic_method)) # revealed: tuple[U]
reveal_type(generic_context(C.generic_method)) # revealed: tuple[U@generic_method]
reveal_type(generic_context(C[int])) # revealed: None
reveal_type(generic_context(C[int].method)) # revealed: None
reveal_type(generic_context(C[int].generic_method)) # revealed: tuple[U]
reveal_type(generic_context(C[int].generic_method)) # revealed: tuple[U@generic_method]

c: C[int] = C[int]()
reveal_type(c.generic_method(1, "string")) # revealed: Literal["string"]
reveal_type(generic_context(c)) # revealed: None
reveal_type(generic_context(c.method)) # revealed: None
reveal_type(generic_context(c.generic_method)) # revealed: tuple[U]
reveal_type(generic_context(c.generic_method)) # revealed: tuple[U@generic_method]
```

## Specializations propagate
Expand Down Expand Up @@ -540,7 +548,8 @@ class WithOverloadedMethod(Generic[T]):
def method(self, x: S | T) -> S | T:
return x

reveal_type(WithOverloadedMethod[int].method) # revealed: Overload[(self, x: int) -> int, (self, x: S) -> S | int]
# revealed: Overload[(self, x: int) -> int, (self, x: S@method) -> S@method | int]
reveal_type(WithOverloadedMethod[int].method)
```

## Cyclic class definitions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ from typing import TypeVar
T = TypeVar("T", bound=int)

def good_param(x: T) -> None:
reveal_type(x) # revealed: T
reveal_type(x) # revealed: T@good_param
```

If the function is annotated as returning the typevar, this means that the upper bound is _not_
Expand All @@ -239,7 +239,7 @@ def good_return(x: T) -> T:
return x

def bad_return(x: T) -> T:
# error: [invalid-return-type] "Return type does not match returned value: expected `T`, found `int`"
# error: [invalid-return-type] "Return type does not match returned value: expected `T@bad_return`, found `int`"
return x + 1
```

Expand All @@ -257,7 +257,7 @@ def different_types(cond: bool, t: T, s: S) -> T:
if cond:
return t
else:
# error: [invalid-return-type] "Return type does not match returned value: expected `T`, found `S`"
# error: [invalid-return-type] "Return type does not match returned value: expected `T@different_types`, found `S@different_types`"
return s

def same_types(cond: bool, t1: T, t2: T) -> T:
Expand All @@ -279,7 +279,7 @@ T = TypeVar("T", int, str)

def same_constrained_types(t1: T, t2: T) -> T:
# TODO: no error
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `T` and `T`"
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `T@same_constrained_types` and `T@same_constrained_types`"
return t1 + t2
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ from typing import Callable, TypeVar
T = TypeVar("T", bound=Callable[[], int])

def bound(f: T):
reveal_type(f) # revealed: T
reveal_type(f) # revealed: T@bound
reveal_type(f()) # revealed: int
```

Expand All @@ -192,7 +192,7 @@ Same with a constrained typevar, as long as all constraints are callable:
T = TypeVar("T", Callable[[], int], Callable[[], str])

def constrained(f: T):
reveal_type(f) # revealed: T
reveal_type(f) # revealed: T@constrained
reveal_type(f()) # revealed: int | str
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ from ty_extensions import generic_context
class SingleTypevar[T]: ...
class MultipleTypevars[T, S]: ...

reveal_type(generic_context(SingleTypevar)) # revealed: tuple[T]
reveal_type(generic_context(MultipleTypevars)) # revealed: tuple[T, S]
# revealed: tuple[T@SingleTypevar]
reveal_type(generic_context(SingleTypevar))
# revealed: tuple[T@MultipleTypevars, S@MultipleTypevars]
reveal_type(generic_context(MultipleTypevars))
```

You cannot use the same typevar more than once.
Expand All @@ -43,9 +45,12 @@ class InheritedGeneric[U, V](MultipleTypevars[U, V]): ...
class InheritedGenericPartiallySpecialized[U](MultipleTypevars[U, int]): ...
class InheritedGenericFullySpecialized(MultipleTypevars[str, int]): ...

reveal_type(generic_context(InheritedGeneric)) # revealed: tuple[U, V]
reveal_type(generic_context(InheritedGenericPartiallySpecialized)) # revealed: tuple[U]
reveal_type(generic_context(InheritedGenericFullySpecialized)) # revealed: None
# revealed: tuple[U@InheritedGeneric, V@InheritedGeneric]
reveal_type(generic_context(InheritedGeneric))
# revealed: tuple[U@InheritedGenericPartiallySpecialized]
reveal_type(generic_context(InheritedGenericPartiallySpecialized))
# revealed: None
reveal_type(generic_context(InheritedGenericFullySpecialized))
```

If you don't specialize a generic base class, we use the default specialization, which maps each
Expand Down Expand Up @@ -406,18 +411,18 @@ class C[T]:
# TODO: error
def cannot_shadow_class_typevar[T](self, t: T): ...

reveal_type(generic_context(C)) # revealed: tuple[T]
reveal_type(generic_context(C)) # revealed: tuple[T@C]
reveal_type(generic_context(C.method)) # revealed: None
reveal_type(generic_context(C.generic_method)) # revealed: tuple[U]
reveal_type(generic_context(C.generic_method)) # revealed: tuple[U@generic_method]
reveal_type(generic_context(C[int])) # revealed: None
reveal_type(generic_context(C[int].method)) # revealed: None
reveal_type(generic_context(C[int].generic_method)) # revealed: tuple[U]
reveal_type(generic_context(C[int].generic_method)) # revealed: tuple[U@generic_method]

c: C[int] = C[int]()
reveal_type(c.generic_method(1, "string")) # revealed: Literal["string"]
reveal_type(generic_context(c)) # revealed: None
reveal_type(generic_context(c.method)) # revealed: None
reveal_type(generic_context(c.generic_method)) # revealed: tuple[U]
reveal_type(generic_context(c.generic_method)) # revealed: tuple[U@generic_method]
```

## Specializations propagate
Expand Down Expand Up @@ -466,7 +471,8 @@ class WithOverloadedMethod[T]:
def method[S](self, x: S | T) -> S | T:
return x

reveal_type(WithOverloadedMethod[int].method) # revealed: Overload[(self, x: int) -> int, (self, x: S) -> S | int]
# revealed: Overload[(self, x: int) -> int, (self, x: S@method) -> S@method | int]
reveal_type(WithOverloadedMethod[int].method)
```

## Cyclic class definitions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ in the function.

```py
def good_param[T: int](x: T) -> None:
reveal_type(x) # revealed: T
reveal_type(x) # revealed: T@good_param
```

If the function is annotated as returning the typevar, this means that the upper bound is _not_
Expand All @@ -215,7 +215,7 @@ def good_return[T: int](x: T) -> T:
return x

def bad_return[T: int](x: T) -> T:
# error: [invalid-return-type] "Return type does not match returned value: expected `T`, found `int`"
# error: [invalid-return-type] "Return type does not match returned value: expected `T@bad_return`, found `int`"
return x + 1
```

Expand All @@ -228,7 +228,7 @@ def different_types[T, S](cond: bool, t: T, s: S) -> T:
if cond:
return t
else:
# error: [invalid-return-type] "Return type does not match returned value: expected `T`, found `S`"
# error: [invalid-return-type] "Return type does not match returned value: expected `T@different_types`, found `S@different_types`"
return s

def same_types[T](cond: bool, t1: T, t2: T) -> T:
Expand All @@ -246,7 +246,7 @@ methods that are compatible with the return type, so the `return` expression is
```py
def same_constrained_types[T: (int, str)](t1: T, t2: T) -> T:
# TODO: no error
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `T` and `T`"
# error: [unsupported-operator] "Operator `+` is unsupported between objects of type `T@same_constrained_types` and `T@same_constrained_types`"
return t1 + t2
```

Expand Down
Loading
Loading