Skip to content

fix(narrowing): preserve reassigned facet types across branches - #5260

Open
rexledesma wants to merge 1 commit into
facebook:mainfrom
rexledesma:fix/conditional-facet-reassignment
Open

rexledesma wants to merge 1 commit into
facebook:mainfrom
rexledesma:fix/conditional-facet-reassignment

Conversation

@rexledesma

Copy link
Copy Markdown
Contributor

Summary

Fixes #5259.

Preserve reassigned attribute and subscript types when merging branches. An unchanged root name does not imply its facets were only narrowed; when a branch widens a facet's type, merge it as a reassignment instead of simplifying back to the earlier type.

AI-assisted implementation and description.

Test Plan

  • Regression cases fail before the fix and pass afterward, covering optional attributes, nested attributes, and TypedDict keys.
  • Library suite: 9,223 passed, 3 ignored. The existing deep_phi_chain_term_expr test overflows the default stack before and after the fix; it passes separately with PYREFLY_STACK_SIZE=67108864.
  • Formatting and linting: python3 test.py --no-test --no-tensor-shapes --no-conformance --no-jsonschema --no-extension.

Attribute and subscript assignments can widen facet types without rebinding their root name. Treat widened facet types as reassignments when merging branches so the merge preserves the new values instead of reverting to the earlier type.
@meta-codesync

meta-codesync Bot commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

This pull request has been imported. If you are a Meta employee, you can view this in D125865538. (Because this pull request was imported automatically, there will not be any future comments.)

@github-actions

Copy link
Copy Markdown

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

============================================================
SUMMARY
============================================================
Total: +32 new errors, -52 fixed errors
By preset: +16/-37 (default), +16/-37 (strict)

Projects with changes (15):
  pip: +2 -2
  cloud-init: +0 -1
  cwltool: +2 -2
  urllib3: +1 -1
  scikit-learn: +3 -3
  setuptools: +0 -1
  pwndbg: +3 -3
  apprise: +2 -2
  yarl: +1 -1
  meson: +0 -1
  core: +2 -2
  xarray: +0 -1
  spack: +14 -7
  pydantic: +0 -23
  discord.py: +2 -2
============================================================

FULL DIFF DETAILS
------------------------------------------------------------

pip (https://github.com/pypa/pip)
- ERROR src/pip/_internal/network/auth.py:555:12-37: Implicit conversion of `None` to `bool` is not allowed [implicit-bool]
+ ERROR src/pip/_internal/network/auth.py:555:12-37: Implicit conversion of `Credentials | None` to `bool` is not allowed [implicit-bool]
- ERROR src/pip/_vendor/urllib3/response.py:778:36-46: Implicit conversion of `None` to `bool` is not allowed [implicit-bool]
+ ERROR src/pip/_vendor/urllib3/response.py:778:36-46: Implicit conversion of `bytes | str | None` to `bool` is not allowed [implicit-bool]

cloud-init (https://github.com/canonical/cloud-init)
- ERROR cloudinit/sources/DataSourceSmartOS.py:672:12-27: Implicit conversion of `Unknown | None` to `bool` is not allowed [implicit-bool]

cwltool (https://github.com/common-workflow-language/cwltool)
- ERROR cwltool/software_requirements.py:68:12-36: Implicit conversion of `None` to `bool` is not allowed [implicit-bool]
+ ERROR cwltool/software_requirements.py:68:12-36: Implicit conversion of `str | Any | None` to `bool` is not allowed [implicit-bool]
- ERROR cwltool/software_requirements.py:68:12-85: Implicit conversion of `None` to `bool` is not allowed [implicit-bool]
+ ERROR cwltool/software_requirements.py:68:12-85: Implicit conversion of `Literal[''] | bool | Any | None` to `bool` is not allowed [implicit-bool]

urllib3 (https://github.com/urllib3/urllib3)
- ERROR src/urllib3/response.py:816:36-46: Implicit conversion of `None` to `bool` is not allowed [implicit-bool]
+ ERROR src/urllib3/response.py:816:36-46: Implicit conversion of `bytes | str | None` to `bool` is not allowed [implicit-bool]

scikit-learn (https://github.com/scikit-learn/scikit-learn)
- ERROR sklearn/gaussian_process/_gpc.py:767:9-39: Result of call expression is of type `_BinaryGaussianProcessClassifierLaplace` and is not used; assign to `_` if this is intentional [unused-call-result]
+ ERROR sklearn/gaussian_process/_gpc.py:767:9-39: Result of call expression is of type `_BinaryGaussianProcessClassifierLaplace | Unknown` and is not used; assign to `_` if this is intentional [unused-call-result]
+ ERROR sklearn/gaussian_process/_gpc.py:778:17-61: Object of type `OneVsOneClassifier | OneVsRestClassifier | _BinaryGaussianProcessClassifierLaplace` has no attribute `log_marginal_likelihood` [missing-attribute]
+ ERROR sklearn/gaussian_process/_gpc.py:888:25-55: The type of attribute `log_marginal_likelihood_value_` is unknown because it comes from an error [unknown-from-error]
- ERROR sklearn/gaussian_process/tests/test_gpc.py:185:12-187:51: `>=` is not supported between `float` and `tuple[float | Unknown, ndarray[Unknown]]` [unsupported-operation]
- ERROR sklearn/gaussian_process/tests/test_gpc.py:185:12-187:51: `>=` is not supported between `tuple[float | Unknown, ndarray[Unknown]]` and `float` [unsupported-operation]

setuptools (https://github.com/pypa/setuptools)
- ERROR setuptools/_distutils/command/bdist.py:131:56-81: `+` is not supported between `Literal['bdist.']` and `None` [unsupported-operation]

pwndbg (https://github.com/pwndbg/pwndbg)
- ERROR pwndbg/aglib/heap/glibc.py:1254:24-45: Implicit conversion of `Literal[0] | None` to `bool` is not allowed [implicit-bool]
+ ERROR pwndbg/aglib/heap/glibc.py:1254:24-45: Implicit conversion of `int | Unknown | None` to `bool` is not allowed [implicit-bool]
- ERROR pwndbg/aglib/heap/glibc.py:1263:52-73: Argument `int | None` is not assignable to parameter `address` with type `int` in function `pwndbg.aglib.memory.is_readable_address` [bad-argument-type]
+ ERROR pwndbg/aglib/heap/glibc.py:1263:52-73: Argument `int | Unknown | None` is not assignable to parameter `address` with type `int` in function `pwndbg.aglib.memory.is_readable_address` [bad-argument-type]
- ERROR pwndbg/aglib/heap/glibc.py:1264:38-59: Argument `int | None` is not assignable to parameter `addr` with type `int` in function `Arena.__init__` [bad-argument-type]
+ ERROR pwndbg/aglib/heap/glibc.py:1264:38-59: Argument `int | Unknown | None` is not assignable to parameter `addr` with type `int` in function `Arena.__init__` [bad-argument-type]

apprise (https://github.com/caronc/apprise)
- ERROR apprise/plugins/email/base.py:425:20-37: Implicit conversion of `bool | str` to `bool` is not allowed [implicit-bool]
+ ERROR apprise/plugins/email/base.py:425:20-37: Implicit conversion of `bool | str | Any` to `bool` is not allowed [implicit-bool]
- ERROR apprise/plugins/simplepush.py:285:24-34: Implicit conversion of `None` to `bool` is not allowed [implicit-bool]
+ ERROR apprise/plugins/simplepush.py:285:24-34: Implicit conversion of `bytes | None` to `bool` is not allowed [implicit-bool]

yarl (https://github.com/aio-libs/yarl)
- ERROR yarl/_url.py:1176:12-50: Implicit conversion of `Literal[0] | str` to `bool` is not allowed [implicit-bool]
+ ERROR yarl/_url.py:1176:12-50: Implicit conversion of `Literal[0, 1] | str` to `bool` is not allowed [implicit-bool]

meson (https://github.com/mesonbuild/meson)
- ERROR mesonbuild/modules/gnome.py:298:16-40: Returned type `str | None` is not assignable to declared return type `str` [bad-return]

core (https://github.com/home-assistant/core)
- ERROR homeassistant/components/fibaro/binary_sensor.py:69:12-36: Implicit conversion of `None` to `bool` is not allowed [implicit-bool]
+ ERROR homeassistant/components/fibaro/binary_sensor.py:69:12-36: Implicit conversion of `Literal['com.fibaro.FGMS001', 'com.fibaro.accelerometer', 'com.fibaro.doorSensor', 'com.fibaro.floodSensor', 'com.fibaro.heatDetector', 'com.fibaro.motionSensor', 'com.fibaro.smokeSensor', 'com.fibaro.windowSensor'] | None` to `bool` is not allowed [implicit-bool]
- ERROR homeassistant/components/panasonic_viera/__init__.py:211:12-28: Implicit conversion of `list[str] | None` to `bool` is not allowed [implicit-bool]
+ ERROR homeassistant/components/panasonic_viera/__init__.py:211:12-28: Implicit conversion of `list[str] | Unknown` to `bool` is not allowed [implicit-bool]

xarray (https://github.com/pydata/xarray)
- ERROR xarray/groupers.py:234:16-36: Returned type `Index | None` is not assignable to declared return type `Index` [bad-return]

spack (https://github.com/spack/spack)
+ ERROR lib/spack/spack/environment/environment.py:229:5-51: Object of class `object` has no attribute `env_path` [missing-attribute]
- ERROR lib/spack/spack/environment/environment.py:269:13-32: Object of class `NoneType` has no attribute `disable` [missing-attribute]
+ ERROR lib/spack/spack/environment/environment.py:269:13-32: Object of type `object | Unknown | None` has no attribute `disable` [missing-attribute]
+ ERROR lib/spack/spack/main.py:701:30-45: The type of this argument is unknown [unknown-argument-type]
- ERROR lib/spack/spack/repo.py:2290:37-51: Object of class `NoneType` has no attribute `repos` [missing-attribute]
+ ERROR lib/spack/spack/repo.py:2290:37-51: Object of type `object | Unknown | None` has no attribute `repos` [missing-attribute]
- ERROR lib/spack/spack/repo.py:2299:5-21: Object of class `NoneType` has no attribute `disable` [missing-attribute]
+ ERROR lib/spack/spack/repo.py:2299:5-21: Object of type `object | Unknown | None` has no attribute `disable` [missing-attribute]
- ERROR lib/spack/spack/repo.py:2306:21-29: Argument `Unknown | None` is not assignable to parameter `repo_path` with type `RepoPath` in function `enable_repo` [bad-argument-type]
+ ERROR lib/spack/spack/repo.py:2306:21-29: Argument `object | Unknown | None` is not assignable to parameter `repo_path` with type `RepoPath` in function `enable_repo` [bad-argument-type]
+ ERROR lib/spack/spack/repo.py:2370:28-50: `object | Unknown | None` is not assignable to variable `repo` with type `Repo | RepoPath | str | None` [bad-assignment]
- ERROR lib/spack/spack/subprocess_context.py:129:31-42: `Unknown | None` is not assignable to attribute `CONFIG` with type `Configuration` [bad-assignment]
+ ERROR lib/spack/spack/subprocess_context.py:129:31-42: `object | Unknown | None` is not assignable to attribute `CONFIG` with type `Configuration` [bad-assignment]
- ERROR lib/spack/spack/subprocess_context.py:130:64-75: Argument `Unknown | None` is not assignable to parameter `config` with type `Configuration` in function `spack.repo.RepoPath.from_config` [bad-argument-type]
+ ERROR lib/spack/spack/subprocess_context.py:130:64-75: Argument `object | Unknown | None` is not assignable to parameter `config` with type `Configuration` in function `spack.repo.RepoPath.from_config` [bad-argument-type]
+ ERROR lib/spack/spack/test/env.py:2296:81-94: Argument `object | Unknown | None` is not assignable to parameter `config` with type `Configuration | None` in function `spack.config.canonicalize_path` [bad-argument-type]
+ ERROR lib/spack/spack/util/lang.py:706:16-35: Cannot index into `object` [bad-index]
+ ERROR lib/spack/spack/util/lang.py:709:16-40: `in` is not supported between `Unknown` and `object` [not-iterable]
+ ERROR lib/spack/spack/util/lang.py:712:16-29: Expected a callable, got `object` [not-callable]
- ERROR lib/spack/spack/util/lang.py:715:20-35: No matching overload found for function `iter` called with arguments: (Unknown | None) [no-matching-overload]
+ ERROR lib/spack/spack/util/lang.py:715:20-35: No matching overload found for function `iter` called with arguments: (object | Unknown | None) [no-matching-overload]

pydantic (https://github.com/pydantic/pydantic)
- ERROR pydantic/v1/fields.py:607:30-40: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `type_` with type `type[Any]` in function `pydantic.v1.typing.is_literal_type` [bad-argument-type]
- ERROR pydantic/v1/fields.py:609:27-37: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `type_` with type `type[Any]` in function `pydantic.v1.typing.is_typeddict` [bad-argument-type]
- ERROR pydantic/v1/fields.py:612:24-34: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `ann_type` with type `type[Any]` in function `pydantic.v1.typing.is_finalvar` [bad-argument-type]
- ERROR pydantic/v1/fields.py:618:39-49: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:623:29-39: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_origin` [bad-argument-type]
- ERROR pydantic/v1/fields.py:626:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:644:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:668:29-39: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:692:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:702:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:712:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:715:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:718:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:722:61-71: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:723:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:726:61-71: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:727:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:730:61-71: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:734:61-71: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:735:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:740:35-45: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:749:108-118: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `tp` with type `type[Any]` in function `pydantic.v1.typing.get_args` [bad-argument-type]
- ERROR pydantic/v1/fields.py:756:50-60: Argument `type[Any] | TypeVar | Any` is not assignable to parameter `type_` with type `type[Any]` in function `ModelField._create_sub_type` [bad-argument-type]

discord.py (https://github.com/Rapptz/discord.py)
- ERROR discord/ext/commands/core.py:1646:12-46: Implicit conversion of `Literal[''] | None` to `bool` is not allowed [implicit-bool]
+ ERROR discord/ext/commands/core.py:1646:12-46: Implicit conversion of `Literal[''] | Command[CogT, ..., Any] | None` to `bool` is not allowed [implicit-bool]
- ERROR discord/ext/commands/core.py:1686:12-46: Implicit conversion of `Literal[''] | None` to `bool` is not allowed [implicit-bool]
+ ERROR discord/ext/commands/core.py:1686:12-46: Implicit conversion of `Literal[''] | Command[CogT, ..., Any] | None` to `bool` is not allowed [implicit-bool]

This branch has not been deployed

No deployments
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.

Conditional attribute reassignment loses the assigned type

2 participants