[ty] ~T should never be assignable to T (#20606)

## Summary

Currently we do not emit an error on this code:

```py
from ty_extensions import Not

def f[T](x: T, y: Not[T]) -> T:
    x = y
    return x
```

But we should do! `~T` should never be assignable to `T`.

This fixes a small regression introduced in
14fe1228e7 (diff-8049ab5af787dba29daa389bbe2b691560c15461ef536f122b1beab112a4b48aR1443-R1446),
where a branch that previously returned `false` was replaced with a
branch that returns `C::always_satisfiable` -- the opposite of what it
used to be! The regression occurred because we didn't have any tests for
this -- so I added some tests in this PR that fail on `main`. I only
spotted the problem because I was going through the code of
`has_relation_to_impl` with a fine toothcomb for
https://github.com/astral-sh/ruff/pull/20602 😄
This commit is contained in:
Alex Waygood 2025-10-02 07:52:47 +01:00 committed by GitHub
parent caf48f4bfc
commit 0639da2552
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 26 additions and 1 deletions

View file

@ -530,3 +530,17 @@ age, name = team.employees[0]
reveal_type(age) # revealed: Age
reveal_type(name) # revealed: Name
```
## `~T` is never assignable to `T`
```py
from typing import TypeVar
from ty_extensions import Not
T = TypeVar("T")
def f(x: T, y: Not[T]) -> T:
x = y # error: [invalid-assignment]
y = x # error: [invalid-assignment]
return x
```

View file

@ -543,3 +543,14 @@ def _(x: int):
reveal_type(C().implicit_self(x)) # revealed: tuple[C, int]
```
## `~T` is never assignable to `T`
```py
from ty_extensions import Not
def f[T](x: T, y: Not[T]) -> T:
x = y # error: [invalid-assignment]
y = x # error: [invalid-assignment]
return x
```

View file

@ -1567,7 +1567,7 @@ impl<'db> Type<'db> {
(Type::Intersection(intersection), Type::NonInferableTypeVar(_))
if intersection.negative(db).contains(&target) =>
{
ConstraintSet::from(true)
ConstraintSet::from(false)
}
// Two identical typevars must always solve to the same type, so they are always