[ty] Support empty function bodies in if TYPE_CHECKING blocks (#19372)

## Summary

Resolves https://github.com/astral-sh/ty/issues/339

Supports having a blank function body inside `if TYPE_CHECKING` block or
in the elif or else of a `if not TYPE_CHECKING` block.

```py
if TYPE_CHECKING:
    def foo() -> int: ...

if not TYPE_CHECKING: ...
else:     
    def bar() -> int: ...
```

## Test Plan

Update `function/return_type.md`

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
This commit is contained in:
Matthew Mckee 2025-07-16 21:48:04 +01:00 committed by GitHub
parent 029de784f1
commit cbe94b094b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 147 additions and 1 deletions

View file

@ -127,6 +127,80 @@ def f(x: int | str):
return x
```
### In `if TYPE_CHECKING` block
Inside an `if TYPE_CHECKING` block, we allow "stub" style function definitions with empty bodies,
since these functions will never actually be called.
```py
from typing import TYPE_CHECKING
if TYPE_CHECKING:
def f() -> int: ...
else:
def f() -> str:
return "hello"
reveal_type(f) # revealed: def f() -> int
if not TYPE_CHECKING:
...
elif True:
def g() -> str: ...
else:
def h() -> str: ...
if not TYPE_CHECKING:
def i() -> int:
return 1
else:
def i() -> str: ...
reveal_type(i) # revealed: def i() -> str
if False:
...
elif TYPE_CHECKING:
def j() -> str: ...
else:
def j_() -> str: ... # error: [invalid-return-type]
if False:
...
elif not TYPE_CHECKING:
def k_() -> str: ... # error: [invalid-return-type]
else:
def k() -> str: ...
class Foo:
if TYPE_CHECKING:
def f(self) -> int: ...
if TYPE_CHECKING:
class Bar:
def f(self) -> int: ...
def get_bool() -> bool:
return True
if TYPE_CHECKING:
if get_bool():
def l() -> str: ...
if get_bool():
if TYPE_CHECKING:
def m() -> str: ...
if TYPE_CHECKING:
if not TYPE_CHECKING:
def n() -> str: ...
```
## Conditional return type
```py