Skip to content

Fix TypeVar resolution order in union type aliases#2056

Closed
Adist319 wants to merge 1 commit into
facebook:mainfrom
Adist319:fix-1759-typevar-resolution-order
Closed

Fix TypeVar resolution order in union type aliases#2056
Adist319 wants to merge 1 commit into
facebook:mainfrom
Adist319:fix-1759-typevar-resolution-order

Conversation

@Adist319
Copy link
Copy Markdown
Contributor

@Adist319 Adist319 commented Jan 9, 2026

Summary

Union type aliases like Result = Ok[_T] | Error[_TE] were collecting type parameters in the wrong order because union members get sorted alphabetically during simplification. This caused Result[T, TE] to incorrectly match T to _TE instead of _T.

The fix sorts collected type parameters by their source location after traversal, restoring the user's intended order.

Fixes #1759.

Test Plan

  • Added test_union_type_alias_typevar_order - original issue reproduction
  • Added test_union_type_alias_typevar_order_multiple - 3 TypeVars with reversed alphabetical order
  • Added test_union_type_alias_duplicate_typevar - same TypeVar appearing multiple times

@meta-cla meta-cla Bot added the cla signed label Jan 9, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jan 9, 2026

Diff from mypy_primer, showing the effect of this PR on open source code:

Expression (https://github.com/cognitedata/Expression)
+  WARN expression/core/fn.py:39:27-50: Redundant cast: `TailCall[_P]` is the same type as `TailCall[_P]` [redundant-cast]
- ERROR expression/core/fn.py:29:30-58: Expected a valid ParamSpec expression, got `_TResult` [invalid-param-spec]
- ERROR expression/core/fn.py:29:30-58: `ParamSpec` cannot be used for type parameter [invalid-param-spec]
- ERROR expression/core/fn.py:37:29-57: Expected a valid ParamSpec expression, got `_TResult` [invalid-param-spec]
- ERROR expression/core/fn.py:37:29-57: `ParamSpec` cannot be used for type parameter [invalid-param-spec]
+  WARN expression/core/fn.py:58:27-50: Redundant cast: `TailCall[_P]` is the same type as `TailCall[_P]` [redundant-cast]
- ERROR expression/core/fn.py:53:46-74: Expected a valid ParamSpec expression, got `_TResult` [invalid-param-spec]
- ERROR expression/core/fn.py:53:46-74: `ParamSpec` cannot be used for type parameter [invalid-param-spec]
- ERROR expression/core/fn.py:56:35-63: Expected a valid ParamSpec expression, got `_TResult` [invalid-param-spec]
- ERROR expression/core/fn.py:56:35-63: `ParamSpec` cannot be used for type parameter [invalid-param-spec]
+ ::warning file=expression/core/fn.py,line=39,col=27,endLine=39,endColumn=50,title=Pyrefly redundant-cast::Redundant cast: `TailCall[_P]` is the same type as `TailCall[_P]`
- ::error file=expression/core/fn.py,line=29,col=30,endLine=29,endColumn=58,title=Pyrefly invalid-param-spec::Expected a valid ParamSpec expression, got `_TResult`
- ::error file=expression/core/fn.py,line=29,col=30,endLine=29,endColumn=58,title=Pyrefly invalid-param-spec::`ParamSpec` cannot be used for type parameter
- ::error file=expression/core/fn.py,line=37,col=29,endLine=37,endColumn=57,title=Pyrefly invalid-param-spec::Expected a valid ParamSpec expression, got `_TResult`
- ::error file=expression/core/fn.py,line=37,col=29,endLine=37,endColumn=57,title=Pyrefly invalid-param-spec::`ParamSpec` cannot be used for type parameter
+ ::warning file=expression/core/fn.py,line=58,col=27,endLine=58,endColumn=50,title=Pyrefly redundant-cast::Redundant cast: `TailCall[_P]` is the same type as `TailCall[_P]`
- ::error file=expression/core/fn.py,line=53,col=46,endLine=53,endColumn=74,title=Pyrefly invalid-param-spec::Expected a valid ParamSpec expression, got `_TResult`
- ::error file=expression/core/fn.py,line=53,col=46,endLine=53,endColumn=74,title=Pyrefly invalid-param-spec::`ParamSpec` cannot be used for type parameter
- ::error file=expression/core/fn.py,line=56,col=35,endLine=56,endColumn=63,title=Pyrefly invalid-param-spec::Expected a valid ParamSpec expression, got `_TResult`
- ::error file=expression/core/fn.py,line=56,col=35,endLine=56,endColumn=63,title=Pyrefly invalid-param-spec::`ParamSpec` cannot be used for type parameter

schemathesis (https://github.com/schemathesis/schemathesis)
- ERROR src/schemathesis/cli/commands/run/handlers/output.py:992:34-48: Object of class `Exception` has no attribute `probes` [missing-attribute]
- ERROR src/schemathesis/engine/events.py:77:14-45: `ProbePayload` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/engine/events.py:81:66-97: `ProbePayload` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/engine/phases/probes.py:41:14-45: `ProbePayload` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/engine/phases/probes.py:54:22-49: Argument `ProbePayload` is not assignable to parameter `value` with type `Exception` in function `schemathesis.core.result.Ok.__init__` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:52:22-57: `APIOperation[Unknown, Unknown, Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:71:30-41: Argument `InvalidSchema` is not assignable to parameter `object` with type `APIOperation[Unknown, Unknown, Unknown]` in function `list.append` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:73:27-39: Argument `APIOperation[Unknown, Unknown, Unknown]` is not assignable to parameter `object` with type `InvalidSchema` in function `list.append` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:228:62-71: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.phases_for` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:236:77-86: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `get_strategy_kwargs` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:237:69-84: Object of class `InvalidSchema` has no attribute `label` [missing-attribute]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:241:39-48: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.generation.hypothesis.builder.create_test` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:245:87-96: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.get_hypothesis_settings` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:259:35-44: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.engine.phases.unit._executor.run_test` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/__init__.py:269:30-35: Argument `APIOperation[Unknown, Unknown, Unknown]` is not assignable to parameter `error` with type `Exception` in function `on_error` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/_layered_scheduler.py:50:33-68: `APIOperation[Unknown, Unknown, Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/engine/phases/unit/_layered_scheduler.py:65:31-64: Argument `APIOperation[Unknown, Unknown, Unknown]` is not assignable to parameter `value` with type `InvalidSchema` in function `schemathesis.core.result.Ok.__init__` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/_layered_scheduler.py:83:32-57: Argument `InvalidSchema` is not assignable to parameter `error` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.core.result.Err.__init__` [bad-argument-type]
- ERROR src/schemathesis/engine/phases/unit/_pool.py:24:41-76: `APIOperation[Unknown, Unknown, Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/engine/phases/unit/_pool.py:28:33-68: `APIOperation[Unknown, Unknown, Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/pytest/lazy.py:48:16-68: `tuple[APIOperation[Unknown, Unknown, Unknown], (...) -> Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/pytest/lazy.py:54:58-67: Argument `InvalidSchema` is not assignable to parameter with type `APIOperation[Unknown, Unknown, Unknown]` [bad-argument-type]
- ERROR src/schemathesis/pytest/lazy.py:60:57-66: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.phases_for` [bad-argument-type]
- ERROR src/schemathesis/pytest/lazy.py:71:27-36: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.generation.hypothesis.builder.create_test` [bad-argument-type]
- ERROR src/schemathesis/pytest/lazy.py:74:90-99: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.get_hypothesis_settings` [bad-argument-type]
- ERROR src/schemathesis/pytest/lazy.py:82:22-39: Argument `tuple[InvalidSchema, (...) -> Unknown]` is not assignable to parameter `value` with type `InvalidSchema` in function `schemathesis.core.result.Ok.__init__` [bad-argument-type]
- ERROR src/schemathesis/pytest/lazy.py:84:19-25: Type of yielded value `Err[APIOperation[Unknown, Unknown, Unknown]]` is not assignable to declared return type `Err[tuple[APIOperation[Unknown, Unknown, Unknown], (...) -> Unknown]] | Ok[InvalidSchema]` [invalid-yield]
- ERROR src/schemathesis/pytest/lazy.py:265:25-44: Type `InvalidSchema` is not iterable [not-iterable]
- ERROR src/schemathesis/pytest/lazy.py:269:49-61: Argument `tuple[APIOperation[Unknown, Unknown, Unknown], (...) -> Unknown]` is not assignable to parameter `error` with type `InvalidSchema` in function `_schema_error` [bad-argument-type]
- ERROR src/schemathesis/pytest/plugin.py:109:34-69: `APIOperation[Unknown, Unknown, Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/pytest/plugin.py:141:62-71: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.auth_for` [bad-argument-type]
- ERROR src/schemathesis/pytest/plugin.py:146:68-77: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.headers_for` [bad-argument-type]
- ERROR src/schemathesis/pytest/plugin.py:150:62-71: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.generation.overrides.for_operation` [bad-argument-type]
- ERROR src/schemathesis/pytest/plugin.py:156:66-75: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.phases_for` [bad-argument-type]
- ERROR src/schemathesis/pytest/plugin.py:167:31-40: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.generation.hypothesis.builder.create_test` [bad-argument-type]
- ERROR src/schemathesis/pytest/plugin.py:171:87-96: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.get_hypothesis_settings` [bad-argument-type]
- ERROR src/schemathesis/pytest/plugin.py:184:40-49: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `SchemathesisCase._get_test_name` [bad-argument-type]
- ERROR src/schemathesis/pytest/plugin.py:187:23-53: Object of class `APIOperation` has no attribute `as_failing_test_function` [missing-attribute]
- ERROR src/schemathesis/schemas.py:311:47-82: `APIOperation[Unknown, Unknown, Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/schemas.py:486:13-39: Object of class `InvalidSchema` has no attribute `as_strategy` [missing-attribute]
- ERROR src/schemathesis/specs/graphql/schemas.py:191:47-82: `APIOperation[Unknown, Unknown, Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/specs/graphql/schemas.py:203:26-35: Argument `APIOperation[Unknown, Unknown, Unknown]` is not assignable to parameter `value` with type `InvalidSchema` in function `schemathesis.core.result.Ok.__init__` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/analysis.py:114:57-72: Object of class `InvalidSchema` has no attribute `label` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/analysis.py:116:29-48: Object of class `InvalidSchema` has no attribute `responses` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/analysis.py:123:35-50: Argument `object` is not assignable to parameter `operation` with type `str` in function `schemathesis.resources.repository.ResourceRepository.record_response` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/analysis.py:192:61-70: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.specs.openapi.warnings.detect_missing_deserializers` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/analysis.py:193:34-49: Object of class `InvalidSchema` has no attribute `label` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/analysis.py:194:63-72: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.specs.openapi.warnings.detect_unsupported_regex` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/analysis.py:195:34-49: Object of class `InvalidSchema` has no attribute `label` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/schemas.py:291:47-82: `APIOperation[Unknown, Unknown, Unknown]` is not assignable to upper bound `Exception` of type variable `E` [bad-specialization]
- ERROR src/schemathesis/specs/openapi/schemas.py:342:38-47: Argument `APIOperation[Unknown, Unknown, Unknown]` is not assignable to parameter `value` with type `InvalidSchema` in function `schemathesis.core.result.Ok.__init__` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/schemas.py:344:35-68: Type of yielded value `Err[InvalidSchema]` is not assignable to declared return type `Err[APIOperation[Unknown, Unknown, Unknown]] | Ok[InvalidSchema]` [invalid-yield]
- ERROR src/schemathesis/specs/openapi/schemas.py:346:23-56: Type of yielded value `Err[InvalidSchema]` is not assignable to declared return type `Err[APIOperation[Unknown, Unknown, Unknown]] | Ok[InvalidSchema]` [invalid-yield]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:120:39-49: Argument `list[InvalidSchema]` is not assignable to parameter `operations` with type `list[APIOperation[Unknown, Unknown, Unknown]]` in function `collect_transitions` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:127:28-47: Object of class `InvalidSchema` has no attribute `responses` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:130:12-27: Object of class `InvalidSchema` has no attribute `label` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:132:48-63: Cannot index into `dict[str, OperationTransitions]` [bad-index]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:138:32-47: Cannot set item in `dict[str, (StepOutput) -> str | None]` [unsupported-operation]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:162:39-49: Argument `list[InvalidSchema]` is not assignable to parameter `operations` with type `list[APIOperation[Unknown, Unknown, Unknown]]` in function `classify_root_transitions` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:165:12-24: Object of class `InvalidSchema` has no attribute `label` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:166:47-59: Cannot index into `dict[str, OperationTransitions]` [bad-index]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:167:61-67: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown] | None` in function `schemathesis.config._projects.ProjectConfig.generation_for` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:173:102-114: Argument `object` is not assignable to parameter `target` with type `str` in function `is_transition_allowed` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:178:56-62: Argument `InvalidSchema` is not assignable to parameter `target` with type `APIOperation[Unknown, Unknown, Unknown]` in function `into_step_input` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:185:37-55: Object of class `InvalidSchema` has no attribute `as_strategy` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:188:33-51: Object of class `InvalidSchema` has no attribute `as_strategy` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:202:60-72: Argument `object` is not assignable to parameter `label` with type `str` in function `is_root_allowed` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/__init__.py:338:33-45: `Exception | NotSet` is not assignable to attribute `body` with type `NotSet | bool | bytes | dict[str, Any] | float | int | list[Unknown] | str` [bad-assignment]
- ERROR src/schemathesis/specs/openapi/stateful/dependencies/__init__.py:67:31-40: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.specs.openapi.stateful.dependencies.inputs.extract_inputs` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/dependencies/__init__.py:74:31-40: Argument `InvalidSchema` is not assignable to parameter `operation` with type `APIOperation[Unknown, Unknown, Unknown]` in function `schemathesis.specs.openapi.stateful.dependencies.outputs.extract_outputs` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/dependencies/__init__.py:80:28-43: Object of class `InvalidSchema` has no attribute `label` [missing-attribute]
- ERROR src/schemathesis/specs/openapi/stateful/dependencies/__init__.py:81:28-44: Argument `str | None` is not assignable to parameter `method` with type `str` in function `schemathesis.specs.openapi.stateful.dependencies.models.OperationNode.__init__` [bad-argument-type]
- ERROR src/schemathesis/specs/openapi/stateful/dependencies/__init__.py:82:26-40: Argument `str | None` is not assignable to parameter `path` with type `str` in function `schemathesis.specs.openapi.stateful.dependencies.models.OperationNode.__init__` [bad-argument-type]
- ::error file=src/schemathesis/cli/commands/run/handlers/output.py,line=992,col=34,endLine=992,endColumn=48,title=Pyrefly missing-attribute::Object of class `Exception` has no attribute `probes`
- ::error file=src/schemathesis/engine/events.py,line=77,col=14,endLine=77,endColumn=45,title=Pyrefly bad-specialization::`ProbePayload` is not assignable to upper bound `Exception` of type variable `E`
- ::error file=src/schemathesis/engine/events.py,line=81,col=66,endLine=81,endColumn=97,title=Pyrefly bad-specialization::`ProbePayload` is not assignable to upper bound `Exception` of type variable `E`
- ::error file=src/schemathesis/engine/phases/probes.py,line=41,col=14,endLine=41,endColumn=45,title=Pyrefly bad-specialization::`ProbePayload` is not assignable to upper bound `Exception` of type variable `E`

... (truncated 69 lines) ...

@meta-codesync
Copy link
Copy Markdown
Contributor

meta-codesync Bot commented Jan 10, 2026

@stroxler has imported this pull request. If you are a Meta employee, you can view this in D90423141.

Copy link
Copy Markdown
Contributor

@stroxler stroxler left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! It looks reasonable to me, I'll aim to get a second review and see if I can get it merged

Copy link
Copy Markdown
Contributor

@grievejia grievejia left a comment

Choose a reason for hiding this comment

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

Review automatically exported from Phabricator review in Meta.

@stroxler stroxler self-assigned this Jan 10, 2026
@meta-codesync meta-codesync Bot closed this in 6bef521 Jan 10, 2026
@meta-codesync
Copy link
Copy Markdown
Contributor

meta-codesync Bot commented Jan 10, 2026

@stroxler merged this pull request in 6bef521.

@yangdanny97
Copy link
Copy Markdown
Contributor

wow, nice work @Adist319!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Order of TypeVar resolution seems incorrect

5 participants