Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion crates/ruff_benchmark/benches/ty_walltime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ static STATIC_FRAME: std::sync::LazyLock<Benchmark<'static>> = std::sync::LazyLo
max_dep_date: "2025-08-09",
python_version: PythonVersion::PY311,
},
600,
630,
)
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1210,11 +1210,7 @@ from typing_extensions import LiteralString

def f(a: Foo, b: list[str], c: list[LiteralString], e):
reveal_type(e) # revealed: Unknown

# TODO: we should select the second overload here and reveal `str`
# (the incorrect result is due to missing logic in protocol subtyping/assignability)
reveal_type(a.join(b)) # revealed: LiteralString

reveal_type(a.join(b)) # revealed: str
reveal_type(a.join(c)) # revealed: LiteralString

# since both overloads match and they have return types that are not equivalent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ from typing import Protocol
import proto_a
import proto_b

# TODO should be error: [invalid-assignment] "Object of type `proto_b.Drawable` is not assignable to `proto_a.Drawable`"
def _(drawable_b: proto_b.Drawable):
# error: [invalid-assignment] "Object of type `proto_b.Drawable` is not assignable to `proto_a.Drawable`"
drawable: proto_a.Drawable = drawable_b
```

Expand Down
12 changes: 4 additions & 8 deletions crates/ty_python_semantic/resources/mdtest/loops/for.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,7 @@ class StrIterator:

def f(x: IntIterator | StrIterator):
for a in x:
# TODO: this should be `int | str` (https://github.com/astral-sh/ty/issues/1089)
reveal_type(a) # revealed: int
reveal_type(a) # revealed: int | str
```

Most real-world iterable types use `Iterator` as the return annotation of their `__iter__` methods:
Expand All @@ -260,14 +259,11 @@ def g(
c: Literal["foo", b"bar"],
):
for x in a:
# TODO: should be `int | str` (https://github.com/astral-sh/ty/issues/1089)
reveal_type(x) # revealed: int
reveal_type(x) # revealed: int | str
for y in b:
# TODO: should be `str | int` (https://github.com/astral-sh/ty/issues/1089)
reveal_type(y) # revealed: str
reveal_type(y) # revealed: str | int
for z in c:
# TODO: should be `LiteralString | int` (https://github.com/astral-sh/ty/issues/1089)
reveal_type(z) # revealed: LiteralString
reveal_type(z) # revealed: LiteralString | int
```

## Union type as iterable where one union element has no `__iter__` method
Expand Down
38 changes: 15 additions & 23 deletions crates/ty_python_semantic/resources/mdtest/protocols.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,11 +617,10 @@ static_assert(is_assignable_to(Foo, HasX))
static_assert(not is_subtype_of(Foo, HasXY))
static_assert(not is_assignable_to(Foo, HasXY))

# TODO: these should pass
static_assert(not is_subtype_of(HasXIntSub, HasX)) # error: [static-assert-error]
static_assert(not is_assignable_to(HasXIntSub, HasX)) # error: [static-assert-error]
static_assert(not is_subtype_of(HasX, HasXIntSub)) # error: [static-assert-error]
static_assert(not is_assignable_to(HasX, HasXIntSub)) # error: [static-assert-error]
static_assert(not is_subtype_of(HasXIntSub, HasX))
static_assert(not is_assignable_to(HasXIntSub, HasX))
static_assert(not is_subtype_of(HasX, HasXIntSub))
static_assert(not is_assignable_to(HasX, HasXIntSub))

class FooSub(Foo): ...

Expand Down Expand Up @@ -2291,10 +2290,9 @@ class MethodPUnrelated(Protocol):

static_assert(is_subtype_of(MethodPSub, MethodPSuper))

# TODO: these should pass
static_assert(not is_assignable_to(MethodPUnrelated, MethodPSuper)) # error: [static-assert-error]
static_assert(not is_assignable_to(MethodPSuper, MethodPUnrelated)) # error: [static-assert-error]
static_assert(not is_assignable_to(MethodPSuper, MethodPSub)) # error: [static-assert-error]
static_assert(not is_assignable_to(MethodPUnrelated, MethodPSuper))
static_assert(not is_assignable_to(MethodPSuper, MethodPUnrelated))
static_assert(not is_assignable_to(MethodPSuper, MethodPSub))
```

## Subtyping between protocols with method members and protocols with non-method members
Expand Down Expand Up @@ -2353,8 +2351,7 @@ And for the same reason, they are never assignable to attribute members (which a
class Attribute(Protocol):
f: Callable[[], bool]

# TODO: should pass
static_assert(not is_assignable_to(Method, Attribute)) # error: [static-assert-error]
static_assert(not is_assignable_to(Method, Attribute))
```

Protocols with attribute members, meanwhile, cannot be assigned to protocols with method members,
Expand All @@ -2363,9 +2360,8 @@ this is not true for attribute members. The same principle also applies for prot
members

```py
# TODO: this should pass
static_assert(not is_assignable_to(PropertyBool, Method)) # error: [static-assert-error]
static_assert(not is_assignable_to(Attribute, Method)) # error: [static-assert-error]
static_assert(not is_assignable_to(PropertyBool, Method))
static_assert(not is_assignable_to(Attribute, Method))
```

But an exception to this rule is if an attribute member is marked as `ClassVar`, as this guarantees
Expand All @@ -2384,9 +2380,8 @@ static_assert(is_assignable_to(ClassVarAttribute, Method))
class ClassVarAttributeBad(Protocol):
f: ClassVar[Callable[[], str]]

# TODO: these should pass:
static_assert(not is_subtype_of(ClassVarAttributeBad, Method)) # error: [static-assert-error]
static_assert(not is_assignable_to(ClassVarAttributeBad, Method)) # error: [static-assert-error]
static_assert(not is_subtype_of(ClassVarAttributeBad, Method))
static_assert(not is_assignable_to(ClassVarAttributeBad, Method))
```

## Narrowing of protocols
Expand Down Expand Up @@ -2707,9 +2702,8 @@ class RecursiveNonFullyStatic(Protocol):
parent: RecursiveNonFullyStatic
x: Any

# TODO: these should pass, once we take into account types of members
static_assert(not is_subtype_of(RecursiveFullyStatic, RecursiveNonFullyStatic)) # error: [static-assert-error]
static_assert(not is_subtype_of(RecursiveNonFullyStatic, RecursiveFullyStatic)) # error: [static-assert-error]
static_assert(not is_subtype_of(RecursiveFullyStatic, RecursiveNonFullyStatic))
static_assert(not is_subtype_of(RecursiveNonFullyStatic, RecursiveFullyStatic))

static_assert(is_assignable_to(RecursiveNonFullyStatic, RecursiveNonFullyStatic))
static_assert(is_assignable_to(RecursiveFullyStatic, RecursiveNonFullyStatic))
Expand All @@ -2727,9 +2721,7 @@ class RecursiveOptionalParent(Protocol):
static_assert(is_assignable_to(RecursiveOptionalParent, RecursiveOptionalParent))

# Due to invariance of mutable attribute members, neither is assignable to the other
#
# TODO: should pass
static_assert(not is_assignable_to(RecursiveNonFullyStatic, RecursiveOptionalParent)) # error: [static-assert-error]
static_assert(not is_assignable_to(RecursiveNonFullyStatic, RecursiveOptionalParent))
static_assert(not is_assignable_to(RecursiveOptionalParent, RecursiveNonFullyStatic))

class Other(Protocol):
Expand Down
Loading