ruff/crates/ty_python_semantic/resources/mdtest/annotations
InSync 6d56ee803e
[ty] Add partial support for TypeIs (#18589)
## Summary

Part of [#117](https://github.com/astral-sh/ty/issues/117).

`TypeIs[]` is a special form that allows users to define their own
narrowing functions. Despite the syntax, `TypeIs` is not a generic and,
on its own, it is meaningless as a type.
[Officially](https://typing.python.org/en/latest/spec/narrowing.html#typeis),
a function annotated as returning a `TypeIs[T]` is a <i>type narrowing
function</i>, where `T` is called the <i>`TypeIs` return type</i>.

A `TypeIs[T]` may or may not be bound to a symbol. Only bound types have
narrowing effect:

```python
def f(v: object = object()) -> TypeIs[int]: ...

a: str = returns_str()

if reveal_type(f()):   # Unbound: TypeIs[int]
	reveal_type(a)     # str

if reveal_type(f(a)):  # Bound:   TypeIs[a, int]
	reveal_type(a)     # str & int
```

Delayed usages of a bound type has no effect, however:

```python
b = f(a)

if b:
	reveal_type(a)     # str
```

A `TypeIs[T]` type:

* Is fully static when `T` is fully static.
* Is a singleton/single-valued when it is bound.
* Has exactly two runtime inhabitants when it is unbound: `True` and
`False`.
  In other words, an unbound type have ambiguous truthiness.
It is possible to infer more precise truthiness for bound types;
however, that is not part of this change.

`TypeIs[T]` is a subtype of or otherwise assignable to `bool`. `TypeIs`
is invariant with respect to the `TypeIs` return type: `TypeIs[int]` is
neither a subtype nor a supertype of `TypeIs[bool]`. When ty sees a
function marked as returning `TypeIs[T]`, its `return`s will be checked
against `bool` instead. ty will also report such functions if they don't
accept a positional argument. Addtionally, a type narrowing function
call with no positional arguments (e.g., `f()` in the example above)
will be considered invalid.

## Test Plan

Markdown tests.

---------

Co-authored-by: Carl Meyer <carl@astral.sh>
2025-06-13 15:27:45 -07:00
..
annotated.md [ty] Add hints to invalid-type-form for common mistakes (#18543) 2025-06-09 00:40:05 +01:00
any.md [ty] Pull types on synthesized Python files created by mdtest (#18539) 2025-06-12 10:32:17 +01:00
callable.md [ty] Pull types on synthesized Python files created by mdtest (#18539) 2025-06-12 10:32:17 +01:00
deferred.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
int_float_complex.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
invalid.md [ty] Add hints to invalid-type-form for common mistakes (#18543) 2025-06-09 00:40:05 +01:00
literal.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
literal_string.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
never.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
new_types.md ty_python_semantic: add union type context to function call type errors 2025-05-09 13:40:51 -04:00
optional.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
self.md [ty] Induct into instances and subclasses when finding and applying generics (#18052) 2025-05-12 21:53:11 -04:00
starred.md [ty] Understand homogeneous tuple annotations (#17998) 2025-05-12 22:02:25 -04:00
stdlib_typing_aliases.md [ty] Support using legacy typing aliases for generic classes in type annotations (#18404) 2025-06-03 12:09:51 +01:00
string.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
union.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00
unsupported_special_forms.md [ty] Add partial support for TypeIs (#18589) 2025-06-13 15:27:45 -07:00
unsupported_special_types.md Generalize special-casing for enums constructed with the functional syntax (#17885) 2025-05-06 11:02:55 +01:00
unsupported_type_qualifiers.md Rename Red Knot (#17820) 2025-05-03 19:49:15 +02:00