Skip to content

[ty] Preserve generic argument types when substituting gradual bounds - #30294

Open
carljm wants to merge 2 commits into
mainfrom
cjm/ty-preserve-generic-argument-evidence
Open

carljm wants to merge 2 commits into
mainfrom
cjm/ty-preserve-generic-argument-evidence

Conversation

@carljm

@carljm carljm commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

A generic function that returns its argument can lose the caller’s type variable when its bound contains Any or Unknown. For example, ty inferred list[Any] for keep(items) here and reported unsound-return-statement when that rule was enabled. It now infers list[T].

from typing import Any

def keep[L: list[Any]](items: L) -> L:
    return items

def forward[T](items: list[T]) -> list[T]:
    return keep(items)

The argument gives the solver list[T] ≤ L, and the return annotation gives it L ≤ list[T]. The solver combines those constraints as L = list[T]. When it checks list[T] against the declared bound list[Any], its invariant comparison records T = Any. That comparison succeeds for every caller specialization of T. Using the recorded equality to rewrite the argument constraint gives list[Any] ≤ L.

The solver previously treated this last step as replacing the argument constraint, so it lost the evidence that the caller passed list[T]. When the replacement uses Any or Unknown from a constraint with declared provenance, ty now records the implication and keeps the original argument constraint available for inference.

Test plan

Compared the four returns in xarray’s _easy_facetgrid on main and with the sequent change alone. All four previously reported FacetGrid[Unknown] where the caller expected FacetGrid[T_DataArrayOrSet]. All four warnings clear with this change.

Ecosystem report

On 0f304c75, the only stable changes were four removed unsound-return-statement warnings in xarray. Each plotting method returns its receiver, and ty now preserves the grid’s data type on all four returns. Full ecosystem report

@carljm carljm added bug An issue describing something that isn't working, or a PR that fixes a bug ty The ty type checker labels Nov 11, 2026
@astral-automations-bot

astral-automations-bot Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Typing conformance results

No changes detected ✅

Current numbers
The percentage of diagnostics emitted that were expected errors held steady at 98.60%. The percentage of expected errors that received a diagnostic held steady at 98.86%. The number of fully passing files held steady at 137/146.

Results for 0f304c7 · Workflow run

@astral-automations-bot

astral-automations-bot Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Memory usage report

Memory usage unchanged ✅


Results for 0f304c7 · Workflow run

@astral-automations-bot

astral-automations-bot Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

ecosystem-analyzer results

Lint rule Added Removed Changed
unsound-return-statement 0 4 0
Total 0 4 0

Flaky changes detected. This PR summary excludes flaky changes; see the HTML report for details.

Raw diff:

xarray (https://github.com/pydata/xarray)
- xarray/plot/facetgrid.py:1096:16 warning[unsound-return-statement] Unsound return statement: `FacetGrid[Unknown]` is not a subtype of `FacetGrid[T_DataArrayOrSet@_easy_facetgrid]`
- xarray/plot/facetgrid.py:1099:16 warning[unsound-return-statement] Unsound return statement: `FacetGrid[Unknown]` is not a subtype of `FacetGrid[T_DataArrayOrSet@_easy_facetgrid]`
- xarray/plot/facetgrid.py:1102:16 warning[unsound-return-statement] Unsound return statement: `FacetGrid[Unknown]` is not a subtype of `FacetGrid[T_DataArrayOrSet@_easy_facetgrid]`
- xarray/plot/facetgrid.py:1105:16 warning[unsound-return-statement] Unsound return statement: `FacetGrid[Unknown]` is not a subtype of `FacetGrid[T_DataArrayOrSet@_easy_facetgrid]`

Full report with detailed diff · Timing results


Results for 0f304c7 · Workflow run

@carljm
carljm marked this pull request as ready for review November 11, 2026 04:08
@carljm
carljm requested a review from a team as a code owner November 11, 2026 04:08
@carljm

carljm commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author
Ecosystem report

PR #30294 ecosystem summary

Four warnings disappeared from xarray’s plotting code. Each affected method returns the grid it was called on. ty now preserves that grid’s data type across the call. These were the only stable diagnostic changes.

Diagnostic changes (1 section)

1. xarray plotting methods preserve the grid’s data type

4 removed unsound-return-statement warnings

Report entries

xarray’s _easy_facetgrid creates a FacetGrid[T] from the caller’s data, then returns the result of a plotting method. Each method annotates its receiver and return with the same type variable, whose bound is the bare FacetGrid. The missing type argument in that bound is Unknown. On the merge base, ty inferred FacetGrid[Unknown] for the return below and warned that it could not guarantee FacetGrid[T]. The PR retains the receiver’s FacetGrid[T], so the return satisfies the annotation. xarray receiver bound

class FacetGrid[T]:
    data: T

    def map_dataarray_line[G: FacetGrid](self: G) -> G:
        return self


def _easy_facetgrid[T](g: FacetGrid[T]) -> FacetGrid[T]:
    return g.map_dataarray_line()

Reproduction

Versions and settings

@carljm
carljm requested review from dcreager and removed request for ibraheemdev November 11, 2026 14:21

This branch was previously deployed

1 inactive deployment
automations — 0f304c75 Deployed Nov 11, 2026 by carljm via security-review / security review #98147
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug An issue describing something that isn't working, or a PR that fixes a bug ty The ty type checker

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant