facebook / facebook/pyrefly

type[Union[A, B, ...]] produces false bad-specialization error when passed to constrained TypeVar parameter

Open
#4,110 0 comments 0 reactions 0 assignees View on GitHub
needs-triage typechecking
Dominant language
Rust
Stars
7k
Forks
516
PR merge metrics
No merged PRs in 30d

Description

### Describe the Bug

Passing a value of `type type[A | B | C]` to a parameter typed `type[T]` where `T` is a constrained TypeVar produces a spurious bad-specialization error, even when every member of the union individually satisfies a constraint.

Reproducer

```python
from typing import TypeVar, Union

TPrimitive = TypeVar("TPrimitive", str, bool, float, int, bytes, None)
ScalarValue = Union[str, bool, float, int, bytes, None]

PRIMITIVE_TYPES: dict[str, type[ScalarValue]] = {
"S8": int,
"double": float,
"char": str,
}

def assertPrimitive(expectedType: type[TPrimitive]) -> TPrimitive: ...

expectedType = PRIMITIVE_TYPES["S8"]
assertPrimitive(expectedType)
```

Actual: `bool | bytes | float | int | str | None is not assignable to any of constraints str, bool, float, int, bytes, None of type variable TPrimitive [bad-specialization]`

Expected: No error. Each member of the union independently satisfies a constraint of TPrimitive.

Note: mypy, pyright, and ty all fail with this same false positive issue

### Sandbox Link

https://pyrefly.org/sandbox/?project=N4IgZglgNgpgziAXKOBDAdgEwEYHsAeAdAA4CeS4ATrgLYAEALqcROgOZ0Q3G6UN0BBdKQA0dAMKooUVNlhiAKsxgA1VJTEBVdBFzoxABWoNcAY1xQAOumsKjXCAwgA3GHQC8dJcVXqAFHSWIHaUDk6uQWJwDBp0eBZiYFC4qAxirGlxpAzwYgByem4AlNYAyqZS6mpQAK5untq66ADadNGx8VCJyanp6JnY2bl0BehuALrW1gYASgCSALJzCnMqAKIA%2BgoAmgZrpYh0mBCmDK3tYkw%2BreWVlNV1dONPHnTA1nSfQaUAHEGHGREHy%2BIEwuBqchg-zoSRSaWBgXAPQY0NhvQRQQAYgBmABMqORQPQn0RmIAbAAWAlwokkoLOXAQTDQq4wAKjYq0kGmAAW6mhF2sAF8puhTDI4HA6AARVKoTG8GipAJGXAmcxQOhFRAIzAwMB0VCSmB8ew0RwuNkIkkkuAwKBgMQwfA%2BU4wTDeGCHVmtEJhS0vIp0AC0AD4vGaLa4dcSbYigkEZjAGDVKMSGDy3HAKjJKHRnFJHuYTaZ3YxcHQAFTO105D3KSuEBMgBOxm2EDuiz3S%2BAmiBSCAALxNr0k0lksFarVlDHlitSTzEQlIT1F1j1BtMlBgqRgkfCMB7dtCA%2BHlACs8obGTh3aWpD4e7vZPUCHJpjJJrMDd9Z8r1mizLKsmw7HspStJe178JMNhthuRzPv2r7DgEmByocM5zpQSr8EGYZ0LcuYPF61qfNuKZpkccqEEax4MPuloBF%2BP6elqCLkamxJ6seSFviAIggGQ25JKQhAmDQUAUAAxHQBikMJUArmgWB4PgdDmOgkBsKmqRNE26AyaUMBuDyDAMMQcCIAA9FZQn6ophC8GwVkwOgVlgqYcBWRpWk6U4ehWTCvCGgW0ATm4PkQNplC6XodC4MQ-noHA%2BlkBmejBq4lBwE0rxBNihAAIz4i2yUxCcDDBjmMiQsGcAQlcrAcJ4MR1NYzQmtQ2UwTUOjcLwdbBsc26nAGngAORRegvAwON1jTZV24AI41BA26YMGADWMCkMGqCmKWkqvONADu6joHN6AgEKAn7QemLQDAFDKTgBAkOQQpAA

### (Only applicable for extension issues) IDE Information

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with the linked Pyrefly sandbox reproducer and trace the bad-specialization diagnostic for a constrained TypeVar receiving a union of types. The issue names no repository files or tests; done means the reproducer no longer reports the false positive and equivalent coverage is added to the relevant type-checker tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.