Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,53 @@

## Basic functionality

<!-- snapshot-diagnostics -->
`assert_never` makes sure that the type of the argument is `Never`.

`assert_never` makes sure that the type of the argument is `Never`. If it is not, a
`type-assertion-failure` diagnostic is emitted.
### Correct usage

```py
from typing_extensions import assert_never, Never, Any
from ty_extensions import Unknown

def _(never: Never, any_: Any, unknown: Unknown, flag: bool):
def _(never: Never):
assert_never(never) # fine
```

### Diagnostics

<!-- snapshot-diagnostics -->

If it is not, a `type-assertion-failure` diagnostic is emitted.

```py
from typing_extensions import assert_never, Never, Any
from ty_extensions import Unknown

def _():
assert_never(0) # error: [type-assertion-failure]

def _():
assert_never("") # error: [type-assertion-failure]

def _():
assert_never(None) # error: [type-assertion-failure]

def _():
assert_never([]) # error: [type-assertion-failure]

def _():
assert_never({}) # error: [type-assertion-failure]

def _():
assert_never(()) # error: [type-assertion-failure]

def _(flag: bool, never: Never):
assert_never(1 if flag else never) # error: [type-assertion-failure]

def _(any_: Any):
assert_never(any_) # error: [type-assertion-failure]

def _(unknown: Unknown):
assert_never(unknown) # error: [type-assertion-failure]
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
expression: snapshot
---
---
mdtest name: assert_never.md - `assert_never` - Basic functionality
mdtest name: assert_never.md - `assert_never` - Basic functionality - Diagnostics
mdtest path: crates/ty_python_semantic/resources/mdtest/directives/assert_never.md
---

Expand All @@ -15,35 +15,47 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/directives/assert_never.
1 | from typing_extensions import assert_never, Never, Any
2 | from ty_extensions import Unknown
3 |
4 | def _(never: Never, any_: Any, unknown: Unknown, flag: bool):
5 | assert_never(never) # fine
4 | def _():
5 | assert_never(0) # error: [type-assertion-failure]
6 |
7 | assert_never(0) # error: [type-assertion-failure]
7 | def _():
8 | assert_never("") # error: [type-assertion-failure]
9 | assert_never(None) # error: [type-assertion-failure]
10 | assert_never([]) # error: [type-assertion-failure]
11 | assert_never({}) # error: [type-assertion-failure]
12 | assert_never(()) # error: [type-assertion-failure]
13 | assert_never(1 if flag else never) # error: [type-assertion-failure]
14 |
15 | assert_never(any_) # error: [type-assertion-failure]
16 | assert_never(unknown) # error: [type-assertion-failure]
9 |
10 | def _():
11 | assert_never(None) # error: [type-assertion-failure]
12 |
13 | def _():
14 | assert_never([]) # error: [type-assertion-failure]
15 |
16 | def _():
17 | assert_never({}) # error: [type-assertion-failure]
18 |
19 | def _():
20 | assert_never(()) # error: [type-assertion-failure]
21 |
22 | def _(flag: bool, never: Never):
23 | assert_never(1 if flag else never) # error: [type-assertion-failure]
24 |
25 | def _(any_: Any):
26 | assert_never(any_) # error: [type-assertion-failure]
27 |
28 | def _(unknown: Unknown):
29 | assert_never(unknown) # error: [type-assertion-failure]
```

# Diagnostics

```
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:7:5
--> src/mdtest_snippet.py:5:5
|
5 | assert_never(never) # fine
6 |
7 | assert_never(0) # error: [type-assertion-failure]
4 | def _():
5 | assert_never(0) # error: [type-assertion-failure]
| ^^^^^^^^^^^^^-^
| |
| Inferred type of argument is `Literal[0]`
8 | assert_never("") # error: [type-assertion-failure]
9 | assert_never(None) # error: [type-assertion-failure]
6 |
7 | def _():
|
info: `Never` and `Literal[0]` are not equivalent types
info: rule `type-assertion-failure` is enabled by default
Expand All @@ -54,13 +66,13 @@ info: rule `type-assertion-failure` is enabled by default
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:8:5
|
7 | assert_never(0) # error: [type-assertion-failure]
7 | def _():
8 | assert_never("") # error: [type-assertion-failure]
| ^^^^^^^^^^^^^--^
| |
| Inferred type of argument is `Literal[""]`
9 | assert_never(None) # error: [type-assertion-failure]
10 | assert_never([]) # error: [type-assertion-failure]
9 |
10 | def _():
|
info: `Never` and `Literal[""]` are not equivalent types
info: rule `type-assertion-failure` is enabled by default
Expand All @@ -69,16 +81,15 @@ info: rule `type-assertion-failure` is enabled by default

```
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:9:5
--> src/mdtest_snippet.py:11:5
|
7 | assert_never(0) # error: [type-assertion-failure]
8 | assert_never("") # error: [type-assertion-failure]
9 | assert_never(None) # error: [type-assertion-failure]
10 | def _():
11 | assert_never(None) # error: [type-assertion-failure]
| ^^^^^^^^^^^^^----^
| |
| Inferred type of argument is `None`
10 | assert_never([]) # error: [type-assertion-failure]
11 | assert_never({}) # error: [type-assertion-failure]
12 |
13 | def _():
|
info: `Never` and `None` are not equivalent types
info: rule `type-assertion-failure` is enabled by default
Expand All @@ -87,16 +98,15 @@ info: rule `type-assertion-failure` is enabled by default

```
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:10:5
--> src/mdtest_snippet.py:14:5
|
8 | assert_never("") # error: [type-assertion-failure]
9 | assert_never(None) # error: [type-assertion-failure]
10 | assert_never([]) # error: [type-assertion-failure]
13 | def _():
14 | assert_never([]) # error: [type-assertion-failure]
| ^^^^^^^^^^^^^--^
| |
| Inferred type of argument is `list[Unknown]`
11 | assert_never({}) # error: [type-assertion-failure]
12 | assert_never(()) # error: [type-assertion-failure]
15 |
16 | def _():
|
info: `Never` and `list[Unknown]` are not equivalent types
info: rule `type-assertion-failure` is enabled by default
Expand All @@ -105,16 +115,15 @@ info: rule `type-assertion-failure` is enabled by default

```
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:11:5
--> src/mdtest_snippet.py:17:5
|
9 | assert_never(None) # error: [type-assertion-failure]
10 | assert_never([]) # error: [type-assertion-failure]
11 | assert_never({}) # error: [type-assertion-failure]
16 | def _():
17 | assert_never({}) # error: [type-assertion-failure]
| ^^^^^^^^^^^^^--^
| |
| Inferred type of argument is `dict[Unknown, Unknown]`
12 | assert_never(()) # error: [type-assertion-failure]
13 | assert_never(1 if flag else never) # error: [type-assertion-failure]
18 |
19 | def _():
|
info: `Never` and `dict[Unknown, Unknown]` are not equivalent types
info: rule `type-assertion-failure` is enabled by default
Expand All @@ -123,15 +132,15 @@ info: rule `type-assertion-failure` is enabled by default

```
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:12:5
--> src/mdtest_snippet.py:20:5
|
10 | assert_never([]) # error: [type-assertion-failure]
11 | assert_never({}) # error: [type-assertion-failure]
12 | assert_never(()) # error: [type-assertion-failure]
19 | def _():
20 | assert_never(()) # error: [type-assertion-failure]
| ^^^^^^^^^^^^^--^
| |
| Inferred type of argument is `tuple[()]`
13 | assert_never(1 if flag else never) # error: [type-assertion-failure]
21 |
22 | def _(flag: bool, never: Never):
|
info: `Never` and `tuple[()]` are not equivalent types
info: rule `type-assertion-failure` is enabled by default
Expand All @@ -140,16 +149,15 @@ info: rule `type-assertion-failure` is enabled by default

```
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:13:5
--> src/mdtest_snippet.py:23:5
|
11 | assert_never({}) # error: [type-assertion-failure]
12 | assert_never(()) # error: [type-assertion-failure]
13 | assert_never(1 if flag else never) # error: [type-assertion-failure]
22 | def _(flag: bool, never: Never):
23 | assert_never(1 if flag else never) # error: [type-assertion-failure]
| ^^^^^^^^^^^^^--------------------^
| |
| Inferred type of argument is `Literal[1]`
14 |
15 | assert_never(any_) # error: [type-assertion-failure]
24 |
25 | def _(any_: Any):
|
info: `Never` and `Literal[1]` are not equivalent types
info: rule `type-assertion-failure` is enabled by default
Expand All @@ -158,15 +166,15 @@ info: rule `type-assertion-failure` is enabled by default

```
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:15:5
--> src/mdtest_snippet.py:26:5
|
13 | assert_never(1 if flag else never) # error: [type-assertion-failure]
14 |
15 | assert_never(any_) # error: [type-assertion-failure]
25 | def _(any_: Any):
26 | assert_never(any_) # error: [type-assertion-failure]
| ^^^^^^^^^^^^^----^
| |
| Inferred type of argument is `Any`
16 | assert_never(unknown) # error: [type-assertion-failure]
27 |
28 | def _(unknown: Unknown):
|
info: `Never` and `Any` are not equivalent types
info: rule `type-assertion-failure` is enabled by default
Expand All @@ -175,10 +183,10 @@ info: rule `type-assertion-failure` is enabled by default

```
error[type-assertion-failure]: Argument does not have asserted type `Never`
--> src/mdtest_snippet.py:16:5
--> src/mdtest_snippet.py:29:5
|
15 | assert_never(any_) # error: [type-assertion-failure]
16 | assert_never(unknown) # error: [type-assertion-failure]
28 | def _(unknown: Unknown):
29 | assert_never(unknown) # error: [type-assertion-failure]
| ^^^^^^^^^^^^^-------^
| |
| Inferred type of argument is `Unknown`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,65 @@ def f():
reveal_type(x) # revealed: Literal[1]
```

## Calls to functions returning `Never` / `NoReturn`

### No implicit return

If we see a call to a function returning `Never`, we should be able to understand that the function
cannot implicitly return `None`. In the below examples, verify that there are no errors emitted for
invalid return type.

```py
from typing import NoReturn
import sys

def f() -> NoReturn:
sys.exit(1)
```

Let's try cases where the function annotated with `NoReturn` is some sub-expression.

```py
from typing import NoReturn
import sys

def _() -> NoReturn:
3 + sys.exit(1)

def _() -> NoReturn:
3 if sys.exit(1) else 4
```

### Type narrowing

```py
from typing import NoReturn
import sys

def g(x: int | None):
if x is None:
sys.exit(1)

# TODO: should be just int, not int | None
reveal_type(x) # revealed: int | None
```

### Bindings after call

These should be understood to be unreachable.

```py
import sys

def _():
x = 3

sys.exit(1)

x = 4
reveal_type(x) # revealed: Never
```

## Nested functions

Free references inside of a function body refer to variables defined in the containing scope.
Expand Down
3 changes: 3 additions & 0 deletions crates/ty_python_semantic/resources/primer/bad.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ hydpy # too many iterations
ibis # too many iterations
jax # too many iterations
mypy # too many iterations (self-recursive type alias)
nox # too many iterations (because of packaging)
packaging # too many iterations
pandas # slow (9s)
pandera # too many iterations
Expand All @@ -19,4 +20,6 @@ setuptools # vendors packaging, see above
spack # slow, success, but mypy-primer hangs processing the output
spark # too many iterations
steam.py # hangs (single threaded)
streamlit # too many iterations (because of packaging)
tornado # bad use-def map (https://github.com/astral-sh/ty/issues/365)
xarray # too many iterations
2 changes: 0 additions & 2 deletions crates/ty_python_semantic/resources/primer/good.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ more-itertools
mypy-protobuf
mypy_primer
nionutils
nox
openlibrary
operator
optuna
Expand Down Expand Up @@ -107,7 +106,6 @@ starlette
static-frame
stone
strawberry
streamlit
svcs
sympy
tornado
Expand Down
Loading
Loading