Wait, your problem is that the static checkers aren't smart enough? I thought that you were complaining about the dynamic checkers.

I think it's unavoidable that they produce different results (see Carl Meyer's explanation). I'm okay with that. In the long run, static type checkers should probably become smarter. E.g. after

x: Literal[1]
y = x+1

we could infer that y's type is Literal[2]. (Maybe pyright already does this?)

On Sat, Sep 18, 2021 at 10:35 AM Paul Bryan <pbryan@anode.ca> wrote:
Thanks for the clarifications. So casting is the solution to avoid this problem with static type checkers?

Switching back to Literals...

def f(x: Literal["A", "B", "C", 1, 2, 3]) -> None:
  if isinstance(x, int):
    g(cast(Literal[1, 2, 3], x))
  else:
    ...

def g(x: Literal[1, 2, 3]) -> None:
  ...


On Sat, 2021-09-18 at 09:27 -0600, Carl Meyer wrote:
On Sat, Sep 18, 2021 at 9:13 AM Carl Meyer <carl@oddbird.net> wrote:
It is true that a Literal type will generally only be statically known
when it originates from a Python literal expression. But this is just
a specific case of the general limitations of static analysis: that
statically-known types are a wider approximation of the actual runtime
types.

To clarify this point: there are many other situations where the same
symptom you observe (static type checking may fail where runtime
checking would pass) can occur without the involvement of Literal
types. Consider this example:

```
def f(x: object) -> None:
    g(x)

def g(x: int) -> None
    ...

f(1)
```

This code must fail static type checking because the call to g(x) is
invalid since it passes an `object` where an `int` is required. The
statically known type of `x` within `f` is only `object`, since
call-sites of `f` will be allowed to pass any object. And yet in the
specific case of the call `f(1)`, where the argument happens to be an
integer, runtime type checking will be fine.

This is exactly analogous to the case you are describing, if we had
instead `g(x: Literal[1]) -> None` and `f(x: int) -> None` -- this is
statically a type error, because the static type check must consider
that `x` could take on any value that is part of the type `int`, even
though any given specific runtime call might check out fine, if `x`
happens to in fact be `1` for that call.

Carl

_______________________________________________
Typing-sig mailing list -- typing-sig@python.org
To unsubscribe send an email to typing-sig-leave@python.org
https://mail.python.org/mailman3/lists/typing-sig.python.org/
Member address: guido@python.org


--
--Guido van Rossum (python.org/~guido)
Pronouns: he/him (why is my pronoun here?)