Repository navigation
Narrow types based on collection containment #2706
Copy link
Copy link
Labels
has-open-prhelp wantedLarger than "good first issue", but still well-defined and ready for someone to pick upLarger than "good first issue", but still well-defined and ready for someone to pick upnarrowingIssues with narrowing - root cause is usually narrowing, flow handling, or bothIssues with narrowing - root cause is usually narrowing, flow handling, or bothtypechecking
Description
Describe the Bug
I just ran into python/mypy#20602 and noticed that pyrefly also doesn't type narrow in some of these cases.
from typing import Literal, reveal_type
LitA = Literal["a"]
lit_dict: dict[LitA, int] = {"a": 1}
lit_tuple: tuple[LitA] = ("a",)
lit_list: list[LitA] = ["a"]
lit_set: set[LitA] = {"a"}
lit_frozenset: frozenset[LitA] = frozenset(("a",))
def no_narrowing(key: str):
if key in lit_dict:
reveal_type(key) # str
lit_dict[key] # Argument `str` is not assignable to parameter `key` with type `Literal['a']`
if key in lit_tuple:
reveal_type(key) # str
if key in lit_list:
reveal_type(key) # str
if key in lit_set:
reveal_type(key) # str
if key in lit_frozenset:
reveal_type(key) # str
if key in frozenset(("a",)):
reveal_type(key) # str
def narrowing(key: str):
if key in ("a",):
reveal_type(key) # Literal['a']
if key in ["a"]:
reveal_type(key) # Literal['a']
if key in {"a"}:
reveal_type(key) # Literal['a']
if key in {"a": 1}:
reveal_type(key) # Literal['a']So it seems to narrow when checking against inline collections, but not if we check against typed variables.
Sandbox Link
No response
(Only applicable for extension issues) IDE Information
No response
Metadata
Metadata
Assignees
Labels
has-open-prhelp wantedLarger than "good first issue", but still well-defined and ready for someone to pick upLarger than "good first issue", but still well-defined and ready for someone to pick upnarrowingIssues with narrowing - root cause is usually narrowing, flow handling, or bothIssues with narrowing - root cause is usually narrowing, flow handling, or bothtypechecking
Activity
yangdanny97 commentedon Mar 7, 2026
Some of these cases might be solved by #2627, which is merged and will be available in the next release. There might be some followup items here to handle all the cases you listed
yangdanny97 commentedon Mar 7, 2026
The sandbox is updated w/ the latest changes. Your lit_dict example works as expected now, but the other ones are not supported yet. It shouldn't be too hard to add, building on top of the dict support added in #2627
JanEricNitschke commentedon May 14, 2026
Also seeing this for narrowing of "str | None" against a "str" collection:
pyrefly
pyright
asukaminato0721 commentedon Jun 24, 2026
#claim
github-actions commentedon Jun 24, 2026
@asukaminato0721 you've claimed this issue — it's now assigned to you. Thanks for picking it up! 🎉
connernilsen commentedon Aug 21, 2026
Looks like most cases are now supported properly (example). I'll add this to the list of issues I plan to work on soon, unless @asukaminato0721 has plans to come back and check out the remaining cases.