`reportPossiblyUnboundVariable` confused by literals
Version: BasedPyright v1.12.0
basedpyright(reportPossiblyUnboundVariable)
As seen below, the snippet has these errors on a, b.
These are well bounded by their literals, so assessing the literal as non-empty (or not) seems to be the limitation.
for c in "foo":
a = c
for c in ("bar",):
b = c
print(a, b)
"a" is possibly unbound
"b" is possibly unbound
i think these are 2 separate unrelated issues:
"a" is possibly unbound"b" is possibly unbound
basedpyright(reportPossiblyUnboundVariable)As seen below, the snippet has these errors on
a, b.These are well bounded by their literals, so assessing the literal as non-empty (or not) seems to be the limitation.
looks like this is an upstream issue that was rejected (https://github.com/microsoft/pyright/issues/7822). i don't see why pyright shouldn't be able to statically determine how many times a tuple with a defined length will be iterated over, because this information is available in the type system.
In addition,
b =does not receive an annotation inlay, whereasddoes. While this makes sense in cases likeevs.fbelow, as the "trivial" case of literal assignment doesn't need an inlay, anything more complicated than direct assignment arguably should receive an inlay, as it is still useful for cases of "indirect assignment", whereb =receiving an infill could be considered helpful, for the purposes of making it obvious that it is a literal. Similarly, withh =as the indirection ofg, it is likely still meaningful to know the result is a literal.Based on the behaviour, I imagine the rule is to show a "helpful" inlay, and that "just" a
Literal[...]is not considered helpful by default. A configuration option for this may be useful, though likely following different modes akin to the type checking; perhaps the current rule isbasic/standardand we havestrictabove that for cases likeb =andh =, with anallfor even showing inlays on assignments likee = "baz".for c in "foo": a = c # a: LiteralString for c in ("bar",): b = c # no inlay print(a, b)for c in (1, 2, 3): d = c # d: Literal[1, 2, 3] e = "baz" # no inlay f = ("baz",) # f: tuple[Literal['baz']] def g(): # g() -> Literal['baz'] return "baz" h = g() # no inlay
this is caused by some heuristic logic that tries to prevent redundant information from being shown in an inlay hint. specifically, we don't display inlay hints for Literals because in this example, the inlay hint : Literal["bar"] would be completely useless because the value is already clearly visible in the string literal:
value = "bar"
but obviously not all Literals are like that. i'll move this to a separate issue: #349
ideally this would also work on range:
for _ in range(1):
a = 1
print(a) # error: possibly undefined
edit: moved this to a separate issue: #815