Now that the initial version of error context collection has been merged, let's collect a few scenarios in which we could improve the diagnostics by adding more (detailed) context:
No short-circuiting
We currently short-circuit on assignability checks. For example, when checking if A | B is assignable to Target, and the assignment A -> Target fails, we already know that the overall assignment will fail. However, this is not ideal for error context collection since we don't get to see if B would have been assignable or not. We should probably play with disabling short-circuiting behavior in the second pass of an assignability check (when we actually collect the error context). This would improve diagnostics like:
Assigning to Iterable (and other commonly used protocols?)
For a list[str] → Iterable[bytes] assignment, we currently emit
error[invalid-assignment]: Object of type `list[str]` is not assignable to `Iterable[bytes]`
--> src/mdtest_snippet.py:4:13
|
4 | target: Iterable[bytes] = source # snapshot
| --------------- ^^^^^^ Incompatible value of type `list[str]`
| |
| Declared type
|
info: type `list[str]` is not assignable to protocol `Iterable[bytes]`
info: └── protocol member `__iter__` is incompatible
info: └── incompatible return types: `Iterator[str]` is not assignable to `Iterator[bytes]`
info: └── protocol `Iterator[str]` is not assignable to protocol `Iterator[bytes]`
info: └── incompatible return types: `str` is not assignable to `bytes`
This is not technically wrong but could certainly be improved with a dedicated hint that summarizes this as something like
info: type `list[str]` is not assignable to protocol `Iterable[bytes]`
info: └── expected an iterator over `bytes`, but got `str`
Better support for callables
- When the number of parameters is incorrect, we should highlight this as the problem. See test here.
- When assigning to and from an overload set, we should highlight problematic overloads. See test here.
- When assigning a class to a
Callable type, we should potentially add the signature of the constructor to the error context (see this test).
Support for TypedDicts
At the very least, we should call out incompatible and missing field. See existing tests here.
Incompatible specializations
When assigning a fully specialized instance of a generic class to another fully specialized instance of that same generic class, we should explain why they are not compatible (including information about the variance of the corresponding type variables). For example, here we should explain that the assignment fails because the second type parameter is contravariant, but bool is not assignable to int:
class MyClass[Covariant, Contravariant, Invariant]:
i: Invariant
def get(self) -> Covariant:
raise
def set(self, value: Contravariant) -> None: ...
def _(source: MyClass[str, bool, bytes]):
target: MyClass[object, int, bytes] = source
Intersection support
This should hopefully be similar to support for unions, just ... dual. See existing tests here.
Type aliases
When type alias are involved, we could add an additional error context node that shows how how we unwrap the type alias (OptionalNumber -> float | None). See test here.
Now that the initial version of error context collection has been merged, let's collect a few scenarios in which we could improve the diagnostics by adding more (detailed) context:
No short-circuiting
We currently short-circuit on assignability checks. For example, when checking if
A | Bis assignable toTarget, and the assignmentA -> Targetfails, we already know that the overall assignment will fail. However, this is not ideal for error context collection since we don't get to see ifBwould have been assignable or not. We should probably play with disabling short-circuiting behavior in the second pass of an assignability check (when we actually collect the error context). This would improve diagnostics like:Assigning to
Iterable(and other commonly used protocols?)For a
list[str]→Iterable[bytes]assignment, we currently emitThis is not technically wrong but could certainly be improved with a dedicated hint that summarizes this as something like
Better support for callables
Callabletype, we should potentially add the signature of the constructor to the error context (see this test).Support for
TypedDictsAt the very least, we should call out incompatible and missing field. See existing tests here.
Incompatible specializations
When assigning a fully specialized instance of a generic class to another fully specialized instance of that same generic class, we should explain why they are not compatible (including information about the variance of the corresponding type variables). For example, here we should explain that the assignment fails because the second type parameter is contravariant, but
boolis not assignable toint:Intersection support
This should hopefully be similar to support for unions, just ... dual. See existing tests here.
Type aliases
When type alias are involved, we could add an additional error context node that shows how how we unwrap the type alias (
OptionalNumber->float | None). See test here.