Skip to content

Commit

Permalink
Add missing test coverage for the changes to is_subtype_of and `is_…
Browse files Browse the repository at this point in the history
…assignable_to`
  • Loading branch information
AlexWaygood committed Jan 27, 2025
1 parent 6991676 commit 7318ff9
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,16 @@ static_assert(is_assignable_to(Never, type[str]))
static_assert(is_assignable_to(Never, type[Any]))
```

### `bool` is assignable to unions that include `bool`

Since we decompose `bool` to `Literal[True, False]` in unions, it would be surprisingly easy to get
this wrong if we forgot to normalize `bool` to `Literal[True, False]` when it appeared on the
left-hand side in `Type::is_assignable_to()`.

```py
from knot_extensions import is_assignable_to, static_assert

static_assert(is_assignable_to(bool, str | bool))
```

[typing documentation]: https://typing.readthedocs.io/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation
Original file line number Diff line number Diff line change
Expand Up @@ -449,5 +449,31 @@ static_assert(not is_subtype_of(Intersection[Unknown, int], int))
static_assert(not is_subtype_of(tuple[int, int], tuple[int, Unknown]))
```

## `bool` is a subtype of `AlwaysTruthy | AlwaysFalsy`

`bool` is equivalent to `Literal[True] | Literal[False]`. `Literal[True]` is a subtype of
`AlwaysTruthy` and `Literal[False]` is a subtype of `AlwaysFalsy`; it therefore stands to reason
that `bool` is a subtype of `AlwaysTruthy | AlwaysFalsy`.

```py
from knot_extensions import AlwaysTruthy, AlwaysFalsy, is_subtype_of, static_assert, Not, is_disjoint_from
from typing_extensions import Literal

static_assert(is_subtype_of(bool, AlwaysTruthy | AlwaysFalsy))

# the inverse also applies -- TODO: this should pass!
# See the TODO comments in the `Type::Intersection` branch of `Type::is_disjoint_from()`.
static_assert(is_disjoint_from(bool, Not[AlwaysTruthy | AlwaysFalsy])) # error: [static-assert-error]

# `Type::is_subtype_of` delegates many questions of `bool` subtyping to `int`,
# but set-theoretic types like intersections and unions are still handled differently to `int`
static_assert(is_subtype_of(Literal[True], Not[Literal[2]]))
static_assert(is_subtype_of(bool, Not[Literal[2]]))
static_assert(is_subtype_of(Literal[True], bool | None))
static_assert(is_subtype_of(bool, bool | None))

static_assert(not is_subtype_of(int, Not[Literal[2]]))
```

[special case for float and complex]: https://typing.readthedocs.io/en/latest/spec/special-types.html#special-cases-for-float-and-complex
[typing documentation]: https://typing.readthedocs.io/en/latest/spec/concepts.html#subtype-supertype-and-type-equivalence

0 comments on commit 7318ff9

Please sign in to comment.