Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect "Type ... is already specialized" error #5449

Closed
HarukaMa opened this issue Jul 9, 2023 · 4 comments
Closed

Incorrect "Type ... is already specialized" error #5449

HarukaMa opened this issue Jul 9, 2023 · 4 comments
Labels
as designed Not a bug, working as intended bug Something isn't working

Comments

@HarukaMa
Copy link

HarukaMa commented Jul 9, 2023

Describe the bug
It seems pyright thinks the cls in generic classmethod is specialized when it's not or has the type erased.

To Reproduce

Consider the code:

from typing import TypeVar, get_args, Type, Any

T = TypeVar('T')

class Tuple(tuple[T, ...]):

    def __new__(cls, value: tuple[T, ...]):
        return tuple.__new__(cls, value)

    @classmethod
    def load(cls, data: BytesIO, *, types: tuple[Type[T], ...]) -> Self:
        print(get_args(cls))
        return cls[*types](data)

Tuple.load(BytesIO(bytes(b"")), types=(int,))

Running pyright gives:

.../scratch.py
  .../scratch.py:13:21 - error: Expected type expression but received "tuple[type[T@Tuple], ...]" (reportGeneralTypeIssues)
  .../scratch.py:13:16 - error: Type "Tuple[T@Tuple]" is already specialized (reportGeneralTypeIssues)
2 errors, 0 warnings, 0 informations

Even if you replace the last line with Tuple[int].load(...), the load method prints (), which means the type is already erased at this point. If you remove the [*types] specialization, the resulting instance of Tuple won't have __orig_class__ attribute, which should indicate the instance was not specialized when it was created.

Expected behavior
pyright should consider the class parameter in the classmethod of generic classes as not specialized.

Code or Screenshots
See above.

VS Code extension or command-line
Command-line, 1.1.316

Additional context
Actually, I'm not sure if the code shown here is the correct usage of generic types. It works for my case though.

@HarukaMa HarukaMa added the bug Something isn't working label Jul 9, 2023
@erictraut
Copy link
Collaborator

Pyright is correct in generating this error, so this isn't a bug.

The cls parameter is already specialized in a class method. For example:

class A(Generic[T]):
    @classmethod
    def m(cls) -> Self:
        return cls()

# The type of `cls` in this case is `A[int]`.
A[int].m()

# The type of `cls` in this case is `A[Unknown]`.
A.m()

Even if cls were not already specialized, your code would be problematic. The symbol cls is a parameter, not the name of a class or a type alias, so the use of an index expression isn't appropriate for purposes of specialization.

If you would like to provide more details about what you're trying to do, I might be able to suggest an alternative approach.

I'm going to close this issue since pyright is doing the right thing here.

@HarukaMa
Copy link
Author

If this is not a bug, then I think we should move this to discussion instead as I do have some questions about the correct usage here.

For example, in your code, the cls and A seems like the exact same thing (runtime-wise); why A[int] is appropriate while cls[int] is not? I can tell from the runtime info that if you return cls(), the returned instance doesn't have the _GenericAlias layer.

My current code has some heavy hacking to get the type info in the code (a class decorator to inject the types to a instance attribute), as my serialization / deserialization routines require the actual type to work properly, and I wanted to make the code as "pretty" as possible.

@erictraut erictraut added the as designed Not a bug, working as intended label Jul 12, 2023
@HarukaMa
Copy link
Author

Could you move this issue to discussion?

@erictraut
Copy link
Collaborator

Please start a new discussion topic and link to this bug report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
as designed Not a bug, working as intended bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants