Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[red-knot] add support for typing.cast #15379

Closed
carljm opened this issue Jan 9, 2025 · 5 comments · Fixed by #15413
Closed

[red-knot] add support for typing.cast #15379

carljm opened this issue Jan 9, 2025 · 5 comments · Fixed by #15413
Labels
help wanted Contributions especially welcome red-knot Multi-file analysis & type inference

Comments

@carljm
Copy link
Contributor

carljm commented Jan 9, 2025

This should be pretty simple to add, once support for assert_type (and functions that take some value expressions and some type expressions) lands.

@carljm carljm added help wanted Contributions especially welcome red-knot Multi-file analysis & type inference labels Jan 9, 2025
@InSyncWithFoo
Copy link
Contributor

InSyncWithFoo commented Jan 10, 2025

I'm working on this. It turned out not to be so simple, due to how bind_call() handles cast()'s signature:

cast(str, True)
let Some((casted_ty, _)) = binding.two_parameter_tys() else { /* ... */ };
//        ^^^^^^^^^ str | Literal[True]

A possible reason is that cast() is defined using overloads and bind_call() can't handle overloads yet:

@overload
def cast(typ: type[_T], val: Any) -> _T: ...
@overload
def cast(typ: str, val: Any) -> Any: ...
@overload
def cast(typ: object, val: Any) -> Any: ...

@InSyncWithFoo
Copy link
Contributor

Open question: Should there be a "strict casting" mode in which a value cannot be casted to a type with which its own inferred type does not overlap (or of which it is not a supertype/subtype)?

Basedpyright calls this reportInvalidCast.

@carljm
Copy link
Contributor Author

carljm commented Jan 10, 2025

turned out not to be so simple, due to how bind_call() handles cast()'s signature

Oh! Yeah, this is because we don't understand overloads, so we treat it as a function defined with an unknown decorator, meaning we currently replace its signature with the "todo signature" (*args: Todo, **kwargs: Todo) -> Todo. So then both positional arguments are bound to the *args parameter.

Short of supporting overloads, which will be a somewhat bigger feature (though we should do it soon), I think the easiest workaround here is to change our definition of the todo signature to (first: Todo = Todo, *args: Todo, **kwargs: Todo) -> Todo. That is, add a first positional argument with default. This signature still accepts any call, but it distinguishes the first parameter such that we can pull out its type separately from call binding.

@carljm
Copy link
Contributor Author

carljm commented Jan 10, 2025

Should there be a "strict casting" mode

I wouldn't add that now. We can certainly consider it as a feature later, but it's not a "table stakes" feature that we need in order to be usable. It's an opinionated extension of the way cast is specified and works in mypy and pyright.

@KotlinIsland
Copy link
Contributor

basedmypy also reports errors with non-overlapping casts
https://mypy-play.net/?mypy=basedmypy-latest&python=3.12&gist=4642a46d5933b8aa9628918383597bc3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Contributions especially welcome red-knot Multi-file analysis & type inference
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants