Skip to content

Fix type narrowing for in operator with union containers and collection views - #11671

Open
Henry Su (hsusul) wants to merge 1 commit into
microsoft:mainfrom
hsusul:fix/container-in-narrowing-union-collections
Open

Fix type narrowing for in operator with union containers and collection views#11671
Henry Su (hsusul) wants to merge 1 commit into
microsoft:mainfrom
hsusul:fix/container-in-narrowing-union-collections

Conversation

@hsusul

Copy link
Copy Markdown
Contributor

Description

This PR fixes type narrowing for the in containment operator when the container operand is a union of containers (e.g. list[str] | tuple[str, ...], list[str] | set[int]) or a standard collection/mapping view (KeysView, ValuesView, dict_keys, dict_values, Sequence, Set, Mapping, etc.).

Previously, getElementTypeForContainerNarrowing only checked for a hardcoded list of concrete builtin classes and failed when containerType was a union or an abstract collection/view from collections.abc / typing. This caused x in container to fail to narrow x when container was a union of container types or a dictionary view.

Changes

  • Updated getElementTypeForContainerNarrowing to handle UnionType containers by extracting and combining element types from all constituent subtypes if all subtypes are supported containers.
  • Added support for stdlib / collections.abc collection types and dictionary views (dict_keys, dict_values, KeysView, ValuesView, Sequence, Set, Mapping, etc.).
  • Added regression tests in typeNarrowingIn1.py.

Validation

  • Ran full test suite in typeEvaluator1.test.ts (159/159 passing).
  • Ran repository checks (pnpm run check and pnpm run typecheck passing cleanly).

@rchiodo

Rich Chiodo (rchiodo) commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

🔒 Automated review in progress — Rich Chiodo (@rchiodo) is auto-reviewing this PR.

reveal_type(v, expected_text="float")
else:
reveal_type(v, expected_text="float | str")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning · Non-blocking recommendation

📍 packages/pyright-internal/src/tests/samples/typeNarrowingIn1.py:227
The tests cover concrete unions and dictionary views but not the newly supported Sequence, Set, Mapping, KeysView, ValuesView, or Container branches. Add focused positive cases plus a custom ABC implementation with permissive __contains__ to establish both intended behavior and the conservative boundary.

[verified]

}

let elementType = containerType.priv.typeArgs[0];
if (containerType.shared.name === 'dict_values' || containerType.shared.name === 'ValuesView') {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Info · Optional note

📍 packages/pyright-internal/src/analyzer/typeGuards.ts:2258
This logic couples narrowing to specific typeshed names and generic argument layouts, particularly the one-versus-two-argument ValuesView handling. Add focused tests for both layouts so future typeshed alias or signature changes cannot silently select the wrong element type.

[verified]

@rchiodo

Copy link
Copy Markdown
Collaborator

Verification: The relevant tests could not be fully run in the isolated environment; this review is not fully verified.

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

@rchiodo Rich Chiodo (rchiodo) added the review-auto:approved Automated review: no blocking findings (approval posted). label Aug 24, 2026

if (!containerType.priv.typeArgs || containerType.priv.typeArgs.length < 1) {
return undefined;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue · Please address or respond

Container[str] (and similarly the newly supported abstract collection interfaces) only promises __contains__(self, x: object) -> bool; a conforming implementation can return True for an int. This path would then narrow that int to str after if x in container. Please restrict narrowing to containers whose membership semantics establish the element-type relationship, and add a custom Container[str] regression case.

reveal_type(v, expected_text="float")
else:
reveal_type(v, expected_text="float | str")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning · Non-blocking recommendation

Please add representative regression coverage for the newly supported typing and collections.abc collection types, such as Sequence, Set, Mapping, Container, KeysView, and ValuesView. The current additions cover unions and concrete dictionary views only, leaving the new module-prefix and generic-layout paths untested.

@rchiodo

Copy link
Copy Markdown
Collaborator

Verification: The relevant tests could not be fully run in the isolated environment; this review is not fully verified.

@rchiodo Rich Chiodo (rchiodo) added review-auto:changes-requested Automated review: posted blocking findings to address. and removed review-auto:approved Automated review: no blocking findings (approval posted). labels Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-auto:changes-requested Automated review: posted blocking findings to address.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants