Skip to content

[ty] Infer generic class pattern specializations - #26420

Closed
charliermarsh wants to merge 12 commits into
mainfrom
charlie/infer-generic-class-pattern-specialization
Closed

[ty] Infer generic class pattern specializations#26420
charliermarsh wants to merge 12 commits into
mainfrom
charlie/infer-generic-class-pattern-specialization

Conversation

@charliermarsh

Copy link
Copy Markdown
Member

Summary

Follow-up to #26411.

When a generic class pattern is a subclass of the subject's class, the subject specialization constrains which pattern-class specializations can match. We previously discarded that relationship and treated members declared by the subclass as Unknown:

from typing import Generic, TypeVar

T = TypeVar("T")

class Base(Generic[T]): ...

class Child(Base[T]):
    item: T

def handle(value: Base[int]) -> None:
    match value:
        case Child(item=item):
            reveal_type(item)  # int

This PR uses the constraint solver to find every specialization of the pattern subclass whose corresponding base is compatible with the subject. It projects the captured member over the complete set of solutions instead of selecting a single preferred type argument. Separate constraint paths remain correlated, and lower and upper bounds are preserved through covariant, contravariant, and invariant member positions.

The same projection handles transformed bases, partially constrained subclasses, TypeVar bounds and constraints, and unconstrained parameters. Runtime matching continues to ignore type-parameter defaults, while generic base patterns and unrelated classes retain the existing conservative behavior.

The focused regression assertions fail on main with Unknown; the full ty_python_semantic suite, workspace Clippy, and repository hooks pass with the new inference.

@astral-sh-bot astral-sh-bot Bot added the ty Multi-file analysis & type inference label Jun 26, 2026
@astral-sh-bot

astral-sh-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 94.47%. The percentage of expected errors that received a diagnostic held steady at 89.19%. The number of fully passing files held steady at 95/134.

@astral-sh-bot

astral-sh-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

Memory usage report

Memory usage unchanged ✅

@astral-sh-bot

astral-sh-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

ecosystem-analyzer results

Lint rule Added Removed Changed
invalid-return-type 21 0 2
invalid-argument-type 12 0 0
invalid-yield 2 0 0
Total 35 0 2
Raw diff (37 changes)
Expression (https://github.com/cognitedata/Expression)
+ expression/collections/maptree.py:503:24 error[invalid-return-type] Return type does not match returned value: expected `tuple[Key@MkIterator, Value@MkIterator]`, found `tuple[SupportsLessThan, object]`
+ expression/core/option.py:73:24 error[invalid-return-type] Return type does not match returned value: expected `_TSourceOut@Option | _TSource@default_value`, found `object`
+ expression/core/option.py:85:24 error[invalid-return-type] Return type does not match returned value: expected `_TSourceOut@Option | _TSource@default_with`, found `object`
+ expression/core/option.py:97:36 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Option`, found `object`
+ expression/core/option.py:109:36 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Option`, found `object`
+ expression/core/option.py:142:31 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Option`, found `object`
+ expression/core/option.py:173:61 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Option`, found `object`
+ expression/core/option.py:182:24 error[invalid-return-type] Return type does not match returned value: expected `list[_TSourceOut@Option]`, found `list[object]`
+ expression/core/option.py:193:24 error[invalid-return-type] Return type does not match returned value: expected `Seq[_TSourceOut@Option]`, found `Seq[object]`
+ expression/core/option.py:232:24 error[invalid-return-type] Return type does not match returned value: expected `_TSourceOut@Option | None`, found `object`
+ expression/core/option.py:242:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TSourceOut@Option, _TError@to_result]`, found `Result[object, _TError@to_result]`
+ expression/core/option.py:252:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TSourceOut@Option, _TError@to_result_with]`, found `Result[object, _TError@to_result_with]`
+ expression/core/option.py:264:24 error[invalid-return-type] Return type does not match returned value: expected `_TSourceOut@Option | None`, found `object`
+ expression/core/option.py:276:24 error[invalid-return-type] Return type does not match returned value: expected `_TSourceOut@Option`, found `object`
+ expression/core/option.py:286:31 error[invalid-yield] Yield type `object` does not match annotated yield type `_TSourceOut@Option`
+ expression/core/option.py:304:24 error[invalid-return-type] Return type does not match returned value: expected `_TSourceOut@Option`, found `object`
+ expression/core/result.py:81:24 error[invalid-return-type] Return type does not match returned value: expected `_TSourceOut@Result | _TSource@default_value`, found `object`
+ expression/core/result.py:93:24 error[invalid-return-type] Return type does not match returned value: expected `_TSource@default_with | _TSourceOut@Result`, found `object`
+ expression/core/result.py:95:31 error[invalid-argument-type] Argument is incorrect: Expected `_TErrorOut@Result`, found `object`
+ expression/core/result.py:105:63 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Result`, found `object`
+ expression/core/result.py:107:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TResult@map, _TErrorOut@Result]`, found `Result[_TResult@map, object]`
+ expression/core/result.py:121:56 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Result`, found `object`
+ expression/core/result.py:123:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TResult@map2, _TErrorOut@Result]`, found `Result[_TResult@map2, object]`
+ expression/core/result.py:133:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TSourceOut@Result, _TResult@map_error]`, found `Result[object, _TResult@map_error]`
+ expression/core/result.py:135:67 error[invalid-argument-type] Argument is incorrect: Expected `_TErrorOut@Result`, found `object`
+ expression/core/result.py:145:31 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Result`, found `object`
+ expression/core/result.py:147:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TResult@bind, _TErrorOut@Result]`, found `Result[_TResult@bind, object]`
+ expression/core/result.py:166:58 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Result`, found `object`
+ expression/core/result.py:184:58 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Result`, found `object`
+ expression/core/result.py:187:38 error[invalid-argument-type] Argument is incorrect: Expected `_TSourceOut@Result`, found `object`
+ expression/core/result.py:198:24 error[invalid-return-type] Return type does not match returned value: expected `dict[str, _TSourceOut@Result | _TErrorOut@Result | Literal["ok", "error"]]`, found `dict[str, object]`
+ expression/core/result.py:203:24 error[invalid-return-type] Return type does not match returned value: expected `dict[str, _TSourceOut@Result | _TErrorOut@Result | Literal["ok", "error"]]`, found `dict[str, object]`
+ expression/core/result.py:236:24 error[invalid-return-type] Return type does not match returned value: expected `Option[_TSourceOut@Result]`, found `Option[object]`
+ expression/core/result.py:255:31 error[invalid-yield] Yield type `object` does not match annotated yield type `_TSourceOut@Result`
+ expression/core/result.py:263:24 error[invalid-return-type] Return type does not match returned value: expected `_TSourceOut@Result`, found `object`
- expression/core/result.py:209:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TErrorOut@Result, _TSourceOut@Result]`, found `Result[_TSourceOut@Result, _TSourceOut@Result]`
+ expression/core/result.py:209:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TErrorOut@Result, _TSourceOut@Result]`, found `Result[Unknown, object]`
- expression/core/result.py:211:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TErrorOut@Result, _TSourceOut@Result]`, found `Result[_TSourceOut@Result, _TSourceOut@Result]`
+ expression/core/result.py:211:24 error[invalid-return-type] Return type does not match returned value: expected `Result[_TErrorOut@Result, _TSourceOut@Result]`, found `Result[object, Unknown]`

Full report with detailed diff (timing results)

Base automatically changed from charlie/match-pattern-binding-followups to main June 26, 2026 20:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant