Skip to content

Promote inferred type to matching constraint for constrained TypeVars#2660

Open
yangdanny97 wants to merge 1 commit intofacebook:mainfrom
yangdanny97:export-D95010963
Open

Promote inferred type to matching constraint for constrained TypeVars#2660
yangdanny97 wants to merge 1 commit intofacebook:mainfrom
yangdanny97:export-D95010963

Conversation

@yangdanny97
Copy link
Contributor

Summary:
I'm hoping we could make some progress towards addressing #2419

The typing spec requires that a constrained TypeVar (T = TypeVar("T", int, str)) resolves to exactly one of its constraint types — never a subtype like bool or Literal[42]. For example, calling f(True) where f[T: (int, str)](x: T) -> T should yield int, not bool.

Previously, the solver pinned the TypeVar to the raw argument type and validated it against the union of constraints. This meant subtypes like bool or user-defined subclasses like MyStr(str) leaked through as the resolved type, causing assert_type failures and spurious errors when mixing a subclass with its base in the same call (e.g., concat(m: MyStr, s: str) would error because str is not assignable to MyStr).

The fix introduces constraint promotion in the TypeVar solving arms of the solver. When we encounter a constrained TypeVar, instead of recording the raw argument type directly, we search for the narrowest constraint the argument is assignable to and pin the TypeVar to that constraint. "Narrowest" means: among all matching constraints, pick the one that is itself a subtype of all others (e.g., for a class D inheriting from both B and C, prefer C over B if both are constraints). If no constraint matches, we report the existing specialization error.

This also happens to resolve conformance failures in generics_basic.py (3 differences → 2; the remaining one is an unrelated AnyStr issue).

Differential Revision: D95010963

Summary:
I'm hoping we could make some progress towards addressing facebook#2419

The typing spec requires that a constrained TypeVar (`T = TypeVar("T", int, str)`) resolves to exactly one of its constraint types — never a subtype like `bool` or `Literal[42]`. For example, calling `f(True)` where `f[T: (int, str)](x: T) -> T` should yield `int`, not `bool`.

Previously, the solver pinned the TypeVar to the raw argument type and validated it against the union of constraints. This meant subtypes like `bool` or user-defined subclasses like `MyStr(str)` leaked through as the resolved type, causing `assert_type` failures and spurious errors when mixing a subclass with its base in the same call (e.g., `concat(m: MyStr, s: str)` would error because `str` is not assignable to `MyStr`).

The fix introduces constraint promotion in the TypeVar solving arms of the solver. When we encounter a constrained TypeVar, instead of recording the raw argument type directly, we search for the narrowest constraint the argument is assignable to and pin the TypeVar to that constraint. "Narrowest" means: among all matching constraints, pick the one that is itself a subtype of all others (e.g., for a class D inheriting from both B and C, prefer C over B if both are constraints). If no constraint matches, we report the existing specialization error.

This also happens to resolve conformance failures in `generics_basic.py` (3 differences → 2; the remaining one is an unrelated `AnyStr` issue).

Differential Revision: D95010963
@meta-cla meta-cla bot added the cla signed label Mar 5, 2026
@meta-codesync
Copy link

meta-codesync bot commented Mar 5, 2026

@yangdanny97 has exported this pull request. If you are a Meta employee, you can view the originating Diff in D95010963.

@github-actions
Copy link

github-actions bot commented Mar 5, 2026

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

trio (https://github.com/python-trio/trio)
+ ERROR src/trio/_file_io.py:269:35-37: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]

colour (https://github.com/colour-science/colour)
+ ERROR colour/models/cie_luv.py:346:18-47: Argument `list[_NestedSequence[bytes | complex | str] | bytes | complex | ndarray[tuple[Any, ...], dtype[float64 | floating[_16Bit] | floating[_32Bit]]] | str]` is not assignable to parameter `a` with type `Buffer | _NestedSequence[bytes | complex | str] | _NestedSequence[_SupportsArray[dtype]] | _SupportsArray[dtype] | bytes | complex | str` in function `colour.utilities.array.tstack` [bad-argument-type]
+ ERROR colour/models/cie_ucs.py:245:22-86: Argument `list[_NestedSequence[bytes | complex | str] | bytes | complex | ndarray[tuple[Any, ...], dtype[float64 | floating[_16Bit] | floating[_32Bit]]] | str]` is not assignable to parameter `a` with type `Buffer | _NestedSequence[bytes | complex | str] | _NestedSequence[_SupportsArray[dtype]] | _SupportsArray[dtype] | bytes | complex | str` in function `colour.utilities.array.tstack` [bad-argument-type]
- ERROR colour/models/cie_xyy.py:284:18-47: Argument `list[_NestedSequence[bytes | complex | str] | bytes | complex | ndarray[tuple[int], dtype[float64 | floating[_16Bit] | floating[_32Bit]]] | str]` is not assignable to parameter `a` with type `Buffer | _NestedSequence[bytes | complex | str] | _NestedSequence[_SupportsArray[dtype]] | _SupportsArray[dtype] | bytes | complex | str` in function `colour.utilities.array.tstack` [bad-argument-type]

hydpy (https://github.com/hydpy-dev/hydpy)
+ ERROR hydpy/auxs/calibtools.py:3169:5-15: Overload signature `(*, rule: type[TypeRule], names: Sequence[str], parameters: Sequence[Parameter | str], values: Sequence[float], lowers: Sequence[float], uppers: Sequence[float], parametersteps: Sequence1 = None, model: ModuleType | str | None = None, selections: None = None) -> list[TypeRule]` is not consistent with implementation signature `(*, rule: type[TypeRule], calibspecs: CalibSpecs | None = None, names: Sequence[str] | None = None, parameters: Sequence[Parameter | str] | None = None, values: Sequence[float] | None = None, keywords: Sequence[str | None] | None = None, lowers: Sequence[float] | None = None, uppers: Sequence[float] | None = None, parametersteps: Sequence1 = None, model: ModuleType | str | None = None, selections: Iterable[Selection | str] | None = None, product: bool = False) -> list[TypeRule]` [inconsistent-overload]
+ ERROR hydpy/auxs/calibtools.py:3184:5-15: Overload signature `(*, rule: type[TypeRule], names: Sequence[str], parameters: Sequence[Parameter | str], values: Sequence[float], keywords: Sequence[str | None] | None = None, lowers: Sequence[float], uppers: Sequence[float], parametersteps: Sequence1 = None, model: ModuleType | str | None = None, selections: Iterable[Selection | str], product: bool = False) -> list[TypeRule]` is not consistent with implementation signature `(*, rule: type[TypeRule], calibspecs: CalibSpecs | None = None, names: Sequence[str] | None = None, parameters: Sequence[Parameter | str] | None = None, values: Sequence[float] | None = None, keywords: Sequence[str | None] | None = None, lowers: Sequence[float] | None = None, uppers: Sequence[float] | None = None, parametersteps: Sequence1 = None, model: ModuleType | str | None = None, selections: Iterable[Selection | str] | None = None, product: bool = False) -> list[TypeRule]` [inconsistent-overload]
+ ERROR hydpy/auxs/calibtools.py:3201:5-15: Overload signature `(*, rule: type[TypeRule], calibspecs: CalibSpecs, names: Sequence[str] | None = None, parameters: Sequence[Parameter | str] | None = None, values: Sequence[float] | None = None, keywords: Sequence[str | None] | None = None, lowers: Sequence[float] | None = None, uppers: Sequence[float] | None = None, model: ModuleType | str | None = None, selections: None = None) -> list[TypeRule]` is not consistent with implementation signature `(*, rule: type[TypeRule], calibspecs: CalibSpecs | None = None, names: Sequence[str] | None = None, parameters: Sequence[Parameter | str] | None = None, values: Sequence[float] | None = None, keywords: Sequence[str | None] | None = None, lowers: Sequence[float] | None = None, uppers: Sequence[float] | None = None, parametersteps: Sequence1 = None, model: ModuleType | str | None = None, selections: Iterable[Selection | str] | None = None, product: bool = False) -> list[TypeRule]` [inconsistent-overload]
+ ERROR hydpy/auxs/calibtools.py:3217:5-15: Overload signature `(*, rule: type[TypeRule], calibspecs: CalibSpecs, names: Sequence[str] | None = None, parameters: Sequence[Parameter | str] | None = None, values: Sequence[float] | None = None, keywords: Sequence[str | None] | None = None, lowers: Sequence[float] | None = None, uppers: Sequence[float] | None = None, model: ModuleType | str | None = None, selections: Iterable[Selection | str], product: bool = False) -> list[TypeRule]` is not consistent with implementation signature `(*, rule: type[TypeRule], calibspecs: CalibSpecs | None = None, names: Sequence[str] | None = None, parameters: Sequence[Parameter | str] | None = None, values: Sequence[float] | None = None, keywords: Sequence[str | None] | None = None, lowers: Sequence[float] | None = None, uppers: Sequence[float] | None = None, parametersteps: Sequence1 = None, model: ModuleType | str | None = None, selections: Iterable[Selection | str] | None = None, product: bool = False) -> list[TypeRule]` [inconsistent-overload]
- ERROR hydpy/core/devicetools.py:2574:36-46: Argument `Literal['-', '--', '-.', ':', 'dashdot', 'dashed', 'dotted', 'solid'] | tuple[LineStyle, LineStyle] | None` is not assignable to parameter `x` with type `Literal['-'] | tuple[Literal['-'] | None, Literal['-'] | None] | None` in function `_make_tuple` [bad-argument-type]
- ERROR hydpy/core/devicetools.py:2757:36-46: Argument `Literal['-', '--', '-.', ':', 'dashdot', 'dashed', 'dotted', 'solid'] | tuple[LineStyle, LineStyle] | None` is not assignable to parameter `x` with type `Literal['-'] | tuple[Literal['-'] | None, Literal['-'] | None] | None` in function `_make_tuple` [bad-argument-type]
+ ERROR hydpy/core/importtools.py:642:9-17: Overload signature `(self: SubmodelAdder[Literal[0], TM_contra, TI_contra], *, wrapped: PrepSub0D[TM_contra, TI_contra], submodelname: str, submodelinterface: type[TI_contra], methods: Iterable[(NoReturn, NoReturn) -> None], dimensionality: TD, landtype_constants: Constants | None, soiltype_constants: Constants | None, landtype_refindices: type[NameParameter] | None, soiltype_refindices: type[NameParameter] | None, refweights: type[Parameter] | None) -> None` is not consistent with implementation signature `(self: Self@SubmodelAdder, *, wrapped: PrepSub0D[TM_contra, TI_contra] | PrepSub1D[TM_contra, TI_contra], submodelname: str, submodelinterface: type[TI_contra], methods: Iterable[(NoReturn, NoReturn) -> None], dimensionality: TD, landtype_constants: Constants | None, soiltype_constants: Constants | None, landtype_refindices: type[NameParameter] | None, soiltype_refindices: type[NameParameter] | None, refweights: type[Parameter] | None) -> None` [inconsistent-overload]
+ ERROR hydpy/core/importtools.py:658:9-17: Overload signature `(self: SubmodelAdder[Literal[1], TM_contra, TI_contra], *, wrapped: PrepSub1D[TM_contra, TI_contra], submodelname: str, submodelinterface: type[TI_contra], methods: Iterable[(NoReturn, NoReturn) -> None], dimensionality: TD, landtype_constants: Constants | None, soiltype_constants: Constants | None, landtype_refindices: type[NameParameter] | None, soiltype_refindices: type[NameParameter] | None, refweights: type[Parameter] | None) -> None` is not consistent with implementation signature `(self: Self@SubmodelAdder, *, wrapped: PrepSub0D[TM_contra, TI_contra] | PrepSub1D[TM_contra, TI_contra], submodelname: str, submodelinterface: type[TI_contra], methods: Iterable[(NoReturn, NoReturn) -> None], dimensionality: TD, landtype_constants: Constants | None, soiltype_constants: Constants | None, landtype_refindices: type[NameParameter] | None, soiltype_refindices: type[NameParameter] | None, refweights: type[Parameter] | None) -> None` [inconsistent-overload]
+ ERROR hydpy/core/parametertools.py:3942:45-59: Cannot index into `float` [bad-index]

tornado (https://github.com/tornadoweb/tornado)
- ERROR tornado/options.py:657:50-64: No matching overload found for function `re.Pattern.match` called with arguments: (str, @_) [no-matching-overload]

Tanjun (https://github.com/FasterSpeeding/Tanjun)
+ ERROR tanjun/context/autocomplete.py:218:15-26: Class member `AutocompleteContext.set_choices` overrides parent class `AutocompleteContext` in an inconsistent manner [bad-override]

core (https://github.com/home-assistant/core)
+ ERROR homeassistant/components/media_source/local_source.py:147:56-65: Argument `BufferedWriter` is not assignable to parameter `fdst` with type `SupportsWrite[str]` in function `shutil.copyfileobj` [bad-argument-type]

koda-validate (https://github.com/keithasaurus/koda-validate)
+ ERROR koda_validate/generic.py:152:55-62: `ExactMatchT` is not assignable to upper bound `Decimal | UUID | bool | bytes | date | datetime | float | int | str` of type variable `ExactMatchT` [bad-specialization]
+ ERROR koda_validate/serialization/json_schema.py:328:20-42: Object of class `int` has no attribute `isoformat` [missing-attribute]
+ ERROR koda_validate/serialization/json_schema.py:349:20-42: Object of class `int` has no attribute `isoformat` [missing-attribute]
+ ERROR koda_validate/serialization/json_schema.py:378:22-42: Object of class `bool` has no attribute `isoformat` [missing-attribute]
+ ERROR koda_validate/serialization/json_schema.py:380:22-42: Object of class `bool` has no attribute `isoformat` [missing-attribute]
+ ERROR koda_validate/serialization/json_schema.py:386:22-39: Object of class `bool` has no attribute `decode` [missing-attribute]

mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ ERROR bson/json_util.py:537:17-33: `bytes | str` is not assignable to upper bound `bytes | str` of type variable `_T` [bad-specialization]
+ ERROR bson/regex.py:83:16-49: Returned type `Regex[str]` is not assignable to declared return type `Regex[_T]` [bad-return]
+ ERROR bson/regex.py:83:21-49: `_T` is not assignable to upper bound `bytes | str` of type variable `_T` [bad-specialization]
+ ERROR bson/regex.py:133:26-52: No matching overload found for function `re.compile` called with arguments: (_T, int) [no-matching-overload]

pydantic (https://github.com/pydantic/pydantic)
+ ERROR pydantic/_internal/_validators.py:174:26-35: No matching overload found for function `re.compile` called with arguments: (PatternType) [no-matching-overload]

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ERROR ddtrace/internal/runtime/container.py:106:43-56: No matching overload found for function `re.Pattern.match` called with arguments: (str | Unknown) [no-matching-overload]
- ERROR ddtrace/internal/runtime/container.py:113:37-50: No matching overload found for function `re.Pattern.match` called with arguments: (str | Unknown) [no-matching-overload]

streamlit (https://github.com/streamlit/streamlit)
- ERROR lib/tests/streamlit/web/server/server_test_case.py:89:13-47: Argument `Literal[b'']` is not assignable to parameter `url` with type `HTTPRequest | str` in function `tornado.websocket.websocket_connect` [bad-argument-type]

cloud-init (https://github.com/canonical/cloud-init)
- ERROR cloudinit/sources/DataSourceCloudCIX.py:90:16-34: Returned type `Literal[b''] | Unknown | None` is not assignable to declared return type `str | None` [bad-return]
- ERROR cloudinit/sources/DataSourceLXD.py:356:53-63: Argument `Literal[b''] | Unknown` is not assignable to parameter `url` with type `str` in function `_get_json_response` [bad-argument-type]
- ERROR cloudinit/sources/DataSourceLXD.py:364:26-42: Argument `Literal[b''] | Unknown` is not assignable to parameter `url` with type `str` in function `_do_request` [bad-argument-type]
- ERROR cloudinit/sources/DataSourceLXD.py:406:30-38: Argument `Literal[b''] | Unknown` is not assignable to parameter `url` with type `str` in function `_do_request` [bad-argument-type]
- ERROR cloudinit/sources/DataSourceLXD.py:412:55-58: Argument `Literal[b''] | Unknown` is not assignable to parameter `url` with type `str` in function `_get_json_response` [bad-argument-type]
- ERROR cloudinit/sources/helpers/ec2.py:119:39-42: Argument `Literal['/']` is not assignable to parameter `suffix` with type `Buffer | tuple[Buffer, ...]` in function `bytes.endswith` [bad-argument-type]
- ERROR cloudinit/sources/helpers/ec2.py:120:17-33: `+=` is not supported between `Literal[b'']` and `Literal['/']` [unsupported-operation]
- ERROR cloudinit/sources/helpers/openstack.py:518:9-19: Class member `MetadataReader._path_join` overrides parent class `BaseReader` in an inconsistent manner [bad-override]
- ERROR cloudinit/url_helper.py:513:26-40: `str | Unknown` is not assignable to TypedDict key `method` with type `Literal[b''] | bool` [bad-typed-dict-key]
- ERROR cloudinit/url_helper.py:516:35-42: `tuple[Unknown, ...]` is not assignable to TypedDict key `timeout` with type `Literal[b''] | bool` [bad-typed-dict-key]
- ERROR cloudinit/url_helper.py:518:35-57: `float` is not assignable to TypedDict key `timeout` with type `Literal[b''] | bool` [bad-typed-dict-key]
- ERROR cloudinit/url_helper.py:548:31-38: `dict[Unknown, Unknown] | Unknown` is not assignable to TypedDict key `headers` with type `Literal[b''] | bool` [bad-typed-dict-key]
- ERROR cloudinit/url_helper.py:554:65-70: Object of class `bool` has no attribute `get`
+ ERROR cloudinit/url_helper.py:554:65-70: Object of class `bool` has no attribute `get` [missing-attribute]
- Object of class `bytes` has no attribute `get` [missing-attribute]
- ERROR cloudinit/url_helper.py:558:25-50: Cannot set item in `Literal[b'']` [unsupported-operation]
- ERROR cloudinit/url_helper.py:590:35-38: Argument `Literal[b'']` is not assignable to parameter `url` with type `str | None` in function `UrlError.__init__` [bad-argument-type]
- ERROR cloudinit/url_helper.py:596:21-24: Argument `Literal[b'']` is not assignable to parameter `url` with type `str | None` in function `UrlError.__init__` [bad-argument-type]
- ERROR cloudinit/url_helper.py:600:41-44: Argument `Literal[b'']` is not assignable to parameter `url` with type `str | None` in function `UrlError.__init__` [bad-argument-type]
- ERROR tests/unittests/helpers.py:160:9-163:46: Pyrefly detected conflicting types while breaking a dependency cycle: `str | Unknown` is not assignable to `LiteralString`. Adding explicit type annotations might possibly help. [bad-assignment]
- ERROR tests/unittests/helpers.py:160:9-163:46: Pyrefly detected conflicting types while breaking a dependency cycle: `str | Unknown` is not assignable to `PathLike[bytes] | bytes`. Adding explicit type annotations might possibly help. [bad-assignment]
- ERROR tests/unittests/sources/test_cloudcix.py:309:17-30: Argument `Literal[b''] | Unknown` is not assignable to parameter `base_url` with type `str` in function `cloudinit.sources.DataSourceCloudCIX.read_metadata` [bad-argument-type]
- ERROR tests/unittests/sources/test_cloudcix.py:333:17-30: Argument `Literal[b''] | Unknown` is not assignable to parameter `base_url` with type `str` in function `cloudinit.sources.DataSourceCloudCIX.read_metadata` [bad-argument-type]

discord.py (https://github.com/Rapptz/discord.py)
+ ERROR discord/app_commands/transformers.py:411:9-16: Class member `LiteralTransformer.choices` overrides parent class `IdentityTransformer` in an inconsistent manner [bad-override]
+ ERROR discord/app_commands/transformers.py:462:9-16: Class member `EnumValueTransformer.choices` overrides parent class `Transformer` in an inconsistent manner [bad-override]
+ ERROR discord/app_commands/transformers.py:489:9-16: Class member `EnumNameTransformer.choices` overrides parent class `Transformer` in an inconsistent manner [bad-override]

setuptools (https://github.com/pypa/setuptools)
+ ERROR setuptools/command/bdist_egg.py:50:37-42: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR setuptools/glob.py:34:22-53: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR setuptools/glob.py:48:16-37: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
- ERROR setuptools/glob.py:70:31-50: No matching overload found for function `glob2` called with arguments: (AnyStr, AnyStr) [no-matching-overload]
+ ERROR setuptools/glob.py:56:38-48: No matching overload found for function `posixpath.split` called with arguments: (AnyStr) [no-matching-overload]
- ERROR setuptools/glob.py:70:31-50: No matching overload found for function `glob1` called with arguments: (AnyStr, AnyStr) [no-matching-overload]
- ERROR setuptools/glob.py:82:32-51: No matching overload found for function `glob2` called with arguments: (AnyStr, AnyStr) [no-matching-overload]
+ ERROR setuptools/glob.py:82:32-51: No matching overload found for function `glob2` called with arguments: (AnyStr, Unknown) [no-matching-overload]
- ERROR setuptools/glob.py:82:32-51: No matching overload found for function `glob1` called with arguments: (AnyStr, AnyStr) [no-matching-overload]
+ ERROR setuptools/glob.py:82:32-51: No matching overload found for function `glob1` called with arguments: (AnyStr, Unknown) [no-matching-overload]

mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ ERROR mitmproxy/flowfilter.py:266:40-66: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:268:41-68: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:280:40-66: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:291:41-68: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:307:34-43: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:313:34-43: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:317:67-81: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:324:44-69: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:326:45-71: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:343:34-43: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:347:59-73: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:354:44-69: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:370:34-43: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:374:63-77: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/flowfilter.py:381:45-71: No matching overload found for function `re.Pattern.search` called with arguments: (bytes) [no-matching-overload]
+ ERROR mitmproxy/net/http/url.py:147:20-28: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR test/mitmproxy/net/http/test_url.py:193:27-45: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR test/mitmproxy/net/http/test_url.py:196:31-48: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR test/mitmproxy/net/http/test_url.py:199:28-45: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]

pyinstrument (https://github.com/joerick/pyinstrument)
+ ERROR pyinstrument/util.py:65:29-39: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]

parso (https://github.com/davidhalter/parso)
+ ERROR parso/python/prefix.py:84:19-30: Object of class `NoneType` has no attribute `group` [missing-attribute]
+ ERROR parso/python/prefix.py:85:17-28: Object of class `NoneType` has no attribute `group` [missing-attribute]
+ ERROR parso/python/prefix.py:96:17-26: Object of class `NoneType` has no attribute `end` [missing-attribute]

aioredis (https://github.com/aio-libs/aioredis)
+ ERROR aioredis/client.py:3138:32-70: `AnyKeyT` is not assignable to upper bound `bytes | memoryview | str` of type variable `AnyKeyT` [bad-specialization]
+ ERROR aioredis/client.py:3417:32-70: `AnyKeyT` is not assignable to upper bound `bytes | memoryview | str` of type variable `AnyKeyT` [bad-specialization]

static-frame (https://github.com/static-frame/static-frame)
+ ERROR static_frame/core/index.py:582:38-57: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/index.py:603:23-27: Argument `Self@Index` is not assignable to parameter `container` with type `Frame` in function `static_frame.core.node_iter.IterNode.__init__` [bad-argument-type]
+ ERROR static_frame/core/index_hierarchy.py:1355:23-27: Argument `Self@IndexHierarchy` is not assignable to parameter `container` with type `Frame` in function `static_frame.core.node_iter.IterNode.__init__` [bad-argument-type]
+ ERROR static_frame/core/node_dt.py:140:30-144:10: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:867:32-71: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:873:41-80: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:879:39-78: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:893:37-43: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:903:45-51: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:913:47-53: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:921:45-62: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:928:45-62: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:941:45-945:10: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:956:37-54: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:975:47-84: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:1002:37-1006:10: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:1033:47-1037:10: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:1048:45-76: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:1057:37-79: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:1079:37-1092:10: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_iter.py:1114:47-1127:10: `TContainerAny` is not assignable to upper bound `Bus | Frame | Quilt | Series | Yarn` of type variable `TContainerAny` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:452:39-56: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:456:38-54: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:487:32-49: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:492:31-47: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:526:38-55: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:531:39-56: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:536:38-54: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:555:37-560:10: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:578:40-584:10: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:653:39-56: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_selector.py:658:38-54: `TVContainer_co` is not assignable to upper bound `Batch | Bus | Frame | FrameAssignILoc | FrameGO | FrameHE | Index | IndexHierarchy | MaskedArray[Any, Any] | Series | SeriesAssign | SeriesHE | TypeBlocks | Yarn | ndarray[Any, Any]` of type variable `TVContainer_co` [bad-specialization]
+ ERROR static_frame/core/node_values.py:79:30-84:10: `TVContainer_co` is not assignable to upper bound `Frame | Index | IndexHierarchy | Series` of type variable `TVContainer_co` [bad-specialization]
- ERROR static_frame/core/type_blocks.py:3700:9-3750:74: Pyrefly detected conflicting types while breaking a dependency cycle: `ndarray[tuple[Any, ...], dtype[numpy.bool]] | Unknown | None` is not assignable to `None`. Adding explicit type annotations might possibly help. [bad-assignment]
+ ERROR static_frame/core/util.py:1429:34-54: No matching overload found for function `numpy._core.multiarray._ConstructorEmpty.__call__` called with arguments: (tuple[int, int] | None, dtype=dtype | Any | None) [no-matching-overload]

prefect (https://github.com/PrefectHQ/prefect)
- ERROR src/prefect/cli/deploy/_core.py:94:33-81: No matching overload found for function `prefect.utilities.templating.apply_values` called with arguments: (dict[str, Any], _Environ[str], remove_notset=Literal[False]) [no-matching-overload]
+ ERROR src/prefect/cli/deploy/_core.py:94:33-81: No matching overload found for function `prefect.utilities.templating.apply_values` called with arguments: (dict[Any, Any], _Environ[str], remove_notset=Literal[False]) [no-matching-overload]
- ERROR src/prefect/cli/deploy/_core.py:376:34-44: Argument `list[dict[str, Any]] | list[Unknown] | type[NotSet] | Unknown` is not assignable to parameter `pull_steps` with type `list[dict[str, Any]]` in function `prefect.cli.deploy._storage._PullStepStorage.__init__` [bad-argument-type]
+ ERROR src/prefect/cli/deploy/_core.py:376:34-44: Argument `list[Any] | type[NotSet]` is not assignable to parameter `pull_steps` with type `list[dict[str, Any]]` in function `prefect.cli.deploy._storage._PullStepStorage.__init__` [bad-argument-type]
- ERROR src/prefect/cli/deploy/_core.py:436:28-46: Argument `list[dict[str, Any]] | list[Unknown] | type[NotSet] | Unknown | None` is not assignable to parameter `pull_steps` with type `list[dict[str, Any]] | None` in function `prefect.deployments.base._save_deployment_to_prefect_file` [bad-argument-type]
+ ERROR src/prefect/cli/deploy/_core.py:436:28-46: Argument `list[Any] | type[NotSet] | None` is not assignable to parameter `pull_steps` with type `list[dict[str, Any]] | None` in function `prefect.deployments.base._save_deployment_to_prefect_file` [bad-argument-type]
- ERROR src/prefect/deployments/steps/core.py:138:26-46: No matching overload found for function `prefect.utilities.templating.apply_values` called with arguments: (dict[str, Any] | dict[Unknown, Unknown], _Environ[str]) [no-matching-overload]
+ ERROR src/prefect/deployments/steps/core.py:138:26-46: No matching overload found for function `prefect.utilities.templating.apply_values` called with arguments: (dict[Any, Any], _Environ[str]) [no-matching-overload]
+ ERROR src/prefect/utilities/templating.py:100:5-17: Overload signature `(template: T, values: dict[str, Any], remove_notset: Literal[True] = True, warn_on_notset: bool = False, skip_prefixes: list[str] | None = None) -> T` is not consistent with implementation signature `(template: T, values: dict[str, Any], remove_notset: bool = True, warn_on_notset: bool = False, skip_prefixes: list[str] | None = None) -> T | type[NotSet]` [inconsistent-overload]
+ ERROR src/prefect/utilities/templating.py:110:5-17: Overload signature `(template: T, values: dict[str, Any], remove_notset: Literal[False] = False, warn_on_notset: bool = False, skip_prefixes: list[str] | None = None) -> T | type[NotSet]` is not consistent with implementation signature `(template: T, values: dict[str, Any], remove_notset: bool = True, warn_on_notset: bool = False, skip_prefixes: list[str] | None = None) -> T | type[NotSet]` [inconsistent-overload]
+ ERROR src/prefect/utilities/templating.py:120:5-17: Overload signature `(template: T, values: dict[str, Any], remove_notset: bool = False, warn_on_notset: bool = False, skip_prefixes: list[str] | None = None) -> T | type[NotSet]` is not consistent with implementation signature `(template: T, values: dict[str, Any], remove_notset: bool = True, warn_on_notset: bool = False, skip_prefixes: list[str] | None = None) -> T | type[NotSet]` [inconsistent-overload]

pip (https://github.com/pypa/pip)
- ERROR src/pip/_internal/network/auth.py:336:16-54: Returned type `Literal[b'']` is not assignable to declared return type `str | None` [bad-return]

jax (https://github.com/google/jax)
+ ERROR jax/_src/pallas/mosaic_gpu/primitives.py:256:35-43: Object of class `TMEMRef` has no attribute `type` [missing-attribute]
+ ERROR jax/_src/pallas/mosaic_gpu/primitives.py:559:26-34: Object of class `TMEMRef` has no attribute `type` [missing-attribute]
+ ERROR jax/_src/pallas/mosaic_gpu/primitives.py:1279:34-40: Object of class `TMEMRef` has no attribute `type` [missing-attribute]
+ ERROR jax/_src/pallas/mosaic_gpu/primitives.py:1338:34-40: Object of class `TMEMRef` has no attribute `type` [missing-attribute]

materialize (https://github.com/MaterializeInc/materialize)
+ ERROR misc/python/materialize/feature_benchmark/report.py:39:25-41: `float` is not assignable to attribute `mean` with type `T | None` [bad-assignment]

kopf (https://github.com/nolar/kopf)
- ERROR kopf/_cogs/structs/references.py:87:51-59: Argument `str` is not assignable to parameter `pat` with type `NamespaceName` in function `fnmatch.fnmatch` [bad-argument-type]
- ERROR kopf/_cogs/structs/references.py:90:61-77: Argument `str` is not assignable to parameter `pat` with type `NamespaceName` in function `fnmatch.fnmatch` [bad-argument-type]
- ERROR kopf/_cogs/structs/references.py:92:73-77: Argument `str` is not assignable to parameter `pat` with type `NamespaceName` in function `fnmatch.fnmatch` [bad-argument-type]

schema_salad (https://github.com/common-workflow-language/schema_salad)
+ ERROR schema_salad/sourceline.py:17:29-40: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR schema_salad/sourceline.py:20:29-40: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]

anyio (https://github.com/agronholm/anyio)
+ ERROR src/anyio/_core/_fileio.py:201:21-27: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR src/anyio/_core/_tempfile.py:108:37-41: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR src/anyio/_core/_tempfile.py:208:37-41: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]

cibuildwheel (https://github.com/pypa/cibuildwheel)
+ ERROR cibuildwheel/logger.py:409:29-39: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]

scrapy (https://github.com/scrapy/scrapy)
+ ERROR scrapy/http/headers.py:32:25-30: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/headers.py:70:9-20: Class member `Headers.__getitem__` overrides parent class `CaselessDict` in an inconsistent manner [bad-override]
+ ERROR scrapy/http/headers.py:72:59-64: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/headers.py:76:9-12: Class member `Headers.get` overrides parent class `CaselessDict` in an inconsistent manner [bad-override]
+ ERROR scrapy/http/headers.py:78:51-65: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/headers.py:84:59-64: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/headers.py:91:9-18: Cannot set item in `Self@Headers` [unsupported-operation]
+ ERROR scrapy/http/headers.py:96:31-50: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/headers.py:99:27-32: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/headers.py:101:9-18: Cannot set item in `Self@Headers` [unsupported-operation]
+ ERROR scrapy/http/request/__init__.py:205:20-48: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/request/__init__.py:320:36-67: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/response/__init__.py:71:40-55: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/response/__init__.py:217:23-231:10: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/response/__init__.py:262:24-276:14: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/response/text.py:161:9-15: Class member `TextResponse.follow` overrides parent class `Response` in an inconsistent manner [bad-override]
+ ERROR scrapy/http/response/text.py:198:30-212:10: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/http/response/text.py:214:9-19: Class member `TextResponse.follow_all` overrides parent class `Response` in an inconsistent manner [bad-override]
+ ERROR scrapy/http/response/text.py:271:34-285:10: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:53:24-29: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:56:52-55: Argument `AnyStr` is not assignable to parameter `key` with type `str` in function `CaselessDict.normkey` [bad-argument-type]
+ ERROR scrapy/utils/datatypes.py:59:45-48: Argument `AnyStr` is not assignable to parameter `key` with type `str` in function `CaselessDict.normkey` [bad-argument-type]
+ ERROR scrapy/utils/datatypes.py:62:45-48: Argument `AnyStr` is not assignable to parameter `key` with type `str` in function `CaselessDict.normkey` [bad-argument-type]
+ ERROR scrapy/utils/datatypes.py:65:52-57: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:83:43-48: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:86:50-55: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:99:43-48: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:112:39-44: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:116:39-44: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:126:39-44: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
+ ERROR scrapy/utils/datatypes.py:131:39-44: `AnyStr` is not assignable to upper bound `bytes | str` of type variable `AnyStr` [bad-specialization]
- ERROR tests/test_proxy_connect.py:95:37-82: Cannot set item in `_Environ[str]` [unsupported-operation]

pwndbg (https://github.com/pwndbg/pwndbg)
+ ERROR pwndbg/commands/got_tracking.py:159:24-33: No matching overload found for function `re.Pattern.match` called with arguments: (str | Unknown | None) [no-matching-overload]

meson (https://github.com/mesonbuild/meson)
+ ERROR mesonbuild/cargo/builder.py:33:29-78: `TV_TokenTypes` is not assignable to upper bound `bool | int | str` of type variable `TV_TokenTypes` [bad-specialization]
+ ERROR mesonbuild/cmake/interpreter.py:1013:70-73: Argument `BaseNode | Path | bool | int | str` is not assignable to parameter `value` with type `bool` in function `mesonbuild.mparser.Token.__init__` [bad-argument-type]
- ERROR mesonbuild/mparser.py:175:35-51: No matching overload found for function `re.Pattern.match` called with arguments: (str, @_) [no-matching-overload]
+ ERROR mesonbuild/mparser.py:231:83-88: Argument `str` is not assignable to parameter `value` with type `bool` in function `Token.__init__` [bad-argument-type]
+ ERROR mesonbuild/mparser.py:725:65-69: Argument `None` is not assignable to parameter `value` with type `bool` in function `Token.__init__` [bad-argument-type]
+ ERROR mesonbuild/mparser.py:751:173-177: Argument `None` is not assignable to parameter `value` with type `bool` in function `Token.__init__` [bad-argument-type]
+ ERROR mesonbuild/mparser.py:860:17-32: `int` is not assignable to attribute `value` with type `bool` [bad-assignment]

altair (https://github.com/vega/altair)
-  WARN altair/utils/schemapi.py:1133:24-84: Redundant cast: `Self@SchemaBase` is the same type as `Self@SchemaBase` [redundant-cast]
+ ERROR altair/vegalite/v6/api.py:1015:37-58: No matching overload found for function `_Conditional.__init__` called with arguments: (condition=_ConditionExtra) [no-matching-overload]
+ ERROR altair/vegalite/v6/api.py:1097:42-64: No matching overload found for function `_Conditional.__init__` called with arguments: (condition=_ConditionClosed) [no-matching-overload]
+ ERROR altair/vegalite/v6/api.py:1200:28-61: `_C` is not assignable to upper bound `list[_ConditionClosed] | _ConditionExtra` of type variable `_C` [bad-specialization]
+ ERROR altair/vegalite/v6/api.py:1203:39-82: `_C` is not assignable to upper bound `list[_ConditionClosed] | _ConditionExtra` of type variable `_C` [bad-specialization]

@github-actions
Copy link

github-actions bot commented Mar 5, 2026

Primer Diff Classification

❌ 9 regression(s) | ✅ 22 improvement(s) | 31 project(s) total

9 regression(s) across trio, colour, hydpy, core, pydantic, materialize, schema_salad, cibuildwheel, pwndbg. error kinds: bad-specialization, bad-argument-type, no-matching-overload. caused by find_matching_constraint(). 22 improvement(s) across tornado, Tanjun, koda-validate, mongo-python-driver, dd-trace-py, streamlit, cloud-init, discord.py, setuptools, mitmproxy, pyinstrument, parso, aioredis, static-frame, prefect, pip, jax, kopf, anyio, scrapy, meson, altair.

Project Verdict Changes Error Kinds Root Cause
trio ❌ Regression +1 bad-specialization find_matching_constraint()
colour ❌ Regression +2, -1 bad-argument-type find_matching_constraint()
hydpy ❌ Regression +7, -2 bad-argument-type, bad-index find_matching_constraint()
tornado ✅ Improvement -1 no-matching-overload find_matching_constraint()
Tanjun ✅ Improvement +1 bad-override find_matching_constraint()
core ❌ Regression +1 bad-argument-type find_matching_constraint()
koda-validate ✅ Improvement +6 missing-attribute on bool/int find_matching_constraint()
mongo-python-driver ✅ Improvement +4 bad-return, bad-specialization find_matching_constraint()
pydantic ❌ Regression +1 no-matching-overload find_matching_constraint()
dd-trace-py ✅ Improvement -2 no-matching-overload find_matching_constraint()
streamlit ✅ Improvement -1 bad-argument-type find_matching_constraint()
cloud-init ✅ Improvement +1, -19 bad-argument-type, bad-assignment find_matching_constraint()
discord.py ✅ Improvement +3 bad-override find_matching_constraint()
setuptools ✅ Improvement +5, -2 bad-specialization find_matching_constraint()
mitmproxy ✅ Improvement +19 bad-specialization, no-matching-overload find_matching_constraint()
pyinstrument ✅ Improvement +1 bad-specialization find_matching_constraint()
parso ✅ Improvement +3 missing-attribute find_matching_constraint()
aioredis ✅ Improvement +2 bad-specialization find_matching_constraint()
static-frame ✅ Improvement +34, -1 bad-argument-type, bad-assignment find_matching_constraint()
prefect ✅ Improvement +7, -4 bad-argument-type, inconsistent-overload find_matching_constraint()
pip ✅ Improvement -1 bad-return find_matching_constraint()
jax ✅ Improvement +4 missing-attribute find_matching_constraint()
materialize ❌ Regression +1 bad-assignment find_matching_constraint()
kopf ✅ Improvement -3 bad-argument-type find_matching_constraint()
schema_salad ❌ Regression +2 bad-specialization find_matching_constraint()
anyio ✅ Improvement +3 bad-specialization find_matching_constraint()
cibuildwheel ❌ Regression +1 bad-specialization find_matching_constraint()
scrapy ✅ Improvement +31, -1 bad-specialization find_matching_constraint()
pwndbg ❌ Regression +1 no-matching-overload find_matching_constraint()
meson ✅ Improvement +6, -1 bad-argument-type, bad-assignment find_matching_constraint()
altair ✅ Improvement +4, -1 TypeVar constraint enforcement find_matching_constraint()
Detailed analysis

❌ Regression (9)

trio (+1)

This is a regression. The error claims AnyStr is not assignable to upper bound bytes | str of type variable AnyStr, but this is incorrect. Looking at line 268, we have async def __anext__(self: AsyncIOWrapper[_CanReadLine[AnyStr]]) -> AnyStr: and line 269 calls await self.readline() which returns AnyStr per the type annotation on line 336: async def readline(self: AsyncIOWrapper[_CanReadLine[AnyStr]], size: int = -1, /) -> AnyStr. The constraint promotion logic introduced in the PR is being overly strict - AnyStr appearing in both the parameter type and return type of the same method should be handled consistently. The typing spec's constraint promotion rule applies when inferring TypeVar bindings from arguments, but here AnyStr is already consistently used throughout the method signature. Mypy and pyright would not flag this pattern because it's a standard use of AnyStr in generic methods.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs is causing this error. The new constraint promotion logic is being applied too broadly - it's treating AnyStr (which appears in both the method parameter and return type) as needing constraint promotion, when the existing type should be valid.

colour (+2, -1)

This is a REGRESSION. The PR correctly implements typing spec compliance for constrained TypeVars, but creates false positive errors in numpy array handling. The errors claim that list[ndarray[...]] is not assignable to parameters expecting _NestedSequence[...] types, but these are actually compatible numpy array types. The tstack() function in the colour library is designed to handle mixed array/scalar inputs through numpy's broadcasting, making these type mismatches spurious. While the constraint promotion logic is spec-compliant, it's producing overly strict type inference that doesn't match how mypy/pyright handle numpy arrays. The removal of the similar error in cie_xyy.py suggests the old behavior was also producing false positives, but the new system creates different false positives rather than fixing the underlying numpy type compatibility issue.
Attribution: The changes to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. The new constraint promotion system is more strict about TypeVar resolution, which affects how numpy array types are inferred and validated in the tstack() calls. The solver now promotes subtypes to their constraint types, changing the inferred types in ways that create new type mismatches with the function signatures.

hydpy (+7, -2)

The constraint promotion changes, while spec-compliant, are causing pyrefly to be overly strict in overload consistency checking and type inference. The hydpy project is mature and well-tested - these errors represent false positives where pyrefly's new constraint handling is too rigid for real-world code patterns that should be valid. The overload signatures were consistent before and the code works correctly at runtime.
Attribution: The changes to constraint promotion logic in find_matching_constraint() and the TypeVar solving arms in pyrefly/lib/solver/solver.rs caused these errors by changing how constrained TypeVars are resolved in complex overloaded functions.

core (+1)

This is a regression. The code is correct - both streams are binary (bytes), so shutil.copyfileobj should accept them. The error occurs because pyrefly's new constraint promotion logic is being overly strict about TypeVar resolution. The function signature copyfileobj(fsrc: SupportsRead[AnyStr], fdst: SupportsWrite[AnyStr]) should allow both parameters to resolve to the same constraint (bytes in this case), but pyrefly is incorrectly inferring one as str and one as bytes. This creates a false positive where working code is flagged as incorrect.
Attribution: The change to find_matching_constraint() in pyrefly/lib/solver/solver.rs is causing stricter constraint resolution for TypeVars. The new logic promotes types to their matching constraints more aggressively, which is affecting the AnyStr constraint resolution in shutil.copyfileobj.

pydantic (+1)

This is a regression. The error occurs because pyrefly's new constraint promotion logic is being too strict during overload resolution. A constrained TypeVar PatternType with constraints (str, bytes) should be compatible with re.compile(pattern: str | bytes) since the TypeVar can only ever be instantiated with types that match the function's parameter. The typing spec supports this - constrained TypeVars should be treated as their constraint union for compatibility purposes. Mypy and pyright handle this correctly, making this a false positive that creates noise for valid code patterns.
Attribution: The change to constraint promotion logic in find_matching_constraint() and the TypeVar solving arms in pyrefly/lib/solver/solver.rs is causing this issue. The new constraint promotion logic appears to be too strict during overload resolution - instead of allowing the constrained TypeVar to match against the union of its constraints for overload purposes, it's treating the unresolved TypeVar as incompatible with re.compile()'s overloads.

materialize (+1)

This is a REGRESSION. The error occurs because pyrefly's new constraint promotion logic is being applied incorrectly. Looking at the code:

  1. T = TypeVar('T', bound=int | float) on line 23 - this is a BOUNDED TypeVar, not a constrained one
  2. mean: T | None on line 30 - the attribute expects T or None
  3. self.mean = mean(set_points) on line 39 - statistics.mean() returns float

The issue is that pyrefly is treating this bounded TypeVar like a constrained TypeVar and trying to promote the float return type. But T is bounded by int | float, meaning T can be any subtype of that union. When T=float (which is valid), then mean: T | None should accept float values.

The constraint promotion logic should only apply to constrained TypeVars (created with TypeVar('T', int, str)), not bounded TypeVars (created with TypeVar('T', bound=int | float)). This is pyrefly being too strict - mypy/pyright would not flag this pattern because the code is correct.

Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused this error. The new constraint promotion mechanism is being applied too broadly - it's promoting the float return type from mean() to match the TypeVar constraint, but then the promoted type doesn't match the expected T | None where T=float.

schema_salad (+2)

These are new bad-specialization errors on AnyStr usage in recursive calls. Looking at the code, _add_lc_filename is defined with parameter source: AnyStr, and the recursive calls on lines 17 and 20 pass source (which is AnyStr) back to the same parameter. The PR implements constraint promotion for constrained TypeVars per the typing spec, which requires that AnyStr (defined as TypeVar('AnyStr', str, bytes)) resolve to exactly one of its constraint types (str or bytes), not remain as the generic AnyStr. However, this creates a type-level inconsistency: when source is promoted to str, it cannot be passed to a parameter expecting bytes, and vice versa. The function signature source: AnyStr means the function should work with either str or bytes, but the constraint promotion makes the recursive calls fail type checking. This is pyrefly being more spec-compliant than mypy/pyright, which handle AnyStr more leniently. While technically correct per the typing spec, this creates false positive noise for a common and valid pattern.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. Specifically, the new constraint promotion behavior in the TypeVar solving arms now promotes AnyStr to its constraint types (str or bytes) rather than keeping it as the raw AnyStr type.

cibuildwheel (+1)

This is a REGRESSION. The error indicates pyrefly is incorrectly treating the AnyStr in file_supports_color and file_is_a_tty as separate type variables that cannot unify, when they should be the same constrained TypeVar. The code is correct - both functions use the same AnyStr import and should accept the same IO[AnyStr] parameter. Mypy and pyright handle this pattern correctly. The new constraint promotion logic is being too strict about TypeVar scoping, creating a false positive where the type variables should unify naturally.
Attribution: The change to constraint promotion logic in find_matching_constraint() and the TypeVar solving arms in pyrefly/lib/solver/solver.rs is now more strictly enforcing TypeVar constraint resolution, which is exposing a scoping issue with how pyrefly handles AnyStr across function boundaries.

pwndbg (+1)

This appears to be a regression. The new constraint promotion logic for TypeVars is causing less precise type inference, resulting in objname being inferred as str | Unknown | None instead of str. The re.Pattern.match() method should accept string arguments, and this code pattern is standard. The presence of Unknown in the inferred type suggests a type inference issue rather than a real bug in the code. Mypy/pyright would likely not flag this pattern.
Attribution: The change to constraint promotion logic in find_matching_constraint() in pyrefly/lib/solver/solver.rs appears to be affecting type inference, causing pyrefly to infer str | Unknown | None instead of just str for the objname variable, leading to the overload resolution failure.

✅ Improvement (22)

tornado (-1)

This is an improvement. The removed error was a false positive caused by pyrefly's failure to properly resolve the constrained TypeVar AnyStr in the context of re.Pattern.match(). The code is actually correct - when calling match() on a pattern compiled from a string with string and int arguments, this should work fine. The PR fixed the TypeVar constraint resolution logic per the typing spec, which requires constrained TypeVars to resolve to exactly one of their constraint types. Previously, pyrefly was showing @_ (unresolved type) instead of properly resolving AnyStr to str, causing spurious overload resolution failures.
Attribution: The change to constraint promotion logic in find_matching_constraint() and the TypeVar solving arms in pyrefly/lib/solver/solver.rs fixed the AnyStr resolution, allowing the overload to match correctly.

Tanjun (+1)

This is an improvement. The PR correctly implements constraint promotion for constrained TypeVars as required by the typing spec. The removed errors were false positives - pyrefly was incorrectly resolving T to MyStr instead of promoting it to the constraint str. With the fix, concat(m, m) correctly returns str (not MyStr), and concat(m, s) is valid because both arguments are promoted to the same constraint type str. The new error on line 44 (bytes not assignable to str) is a legitimate type error being caught. This brings pyrefly into conformance with the typing spec and matches mypy/pyright behavior.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs fixed the TypeVar resolution. Previously, pyrefly pinned TypeVars to the raw argument type (e.g., MyStr), but now it correctly promotes subtypes to their matching constraints (e.g., MyStrstr) as required by the typing spec.

koda-validate (+6)

missing-attribute on bool/int: Real bugs where code calls .isoformat() on bool/int types that don't have this method, exposed by correct constrained TypeVar resolution
bad-specialization: Correct enforcement of constrained TypeVar bounds - the inferred type doesn't match the declared constraints

Overall: These are genuine type safety bugs being caught by pyrefly's improved constrained TypeVar handling. The code has runtime type errors where it calls methods that don't exist on certain types. In koda_validate/generic.py line 152, ExactMatchT is constrained to types including bool, int, str, date, datetime, etc. The JSON schema generation code incorrectly assumes all these types have .isoformat() and .decode() methods, but bool and int don't have isoformat(), and bool doesn't have decode(). The bad-specialization error correctly identifies that the inferred type doesn't match the constraint bounds. This is an improvement - pyrefly is now correctly enforcing the typing spec's requirement that constrained TypeVars resolve to their constraint types, which exposes real bugs in the application code.

Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. Previously, constrained TypeVars like ExactMatchT would resolve to subtypes like bool, but now they correctly promote to the matching constraint type. This exposed that the code was incorrectly assuming all constraint types have methods like isoformat() when only some do.

mongo-python-driver (+4)

These are improvements. The PR implements proper constrained TypeVar resolution per the typing spec. In bson/regex.py, _T = TypeVar('_T', str, bytes) is a constrained TypeVar that must resolve to exactly str or bytes. The error on line 537 in json_util.py shows Regex(pattern, flags) where pattern has type bytes | str - this union type doesn't match either constraint exactly. Similarly, in regex.py line 83, regex.pattern has type _T but the constructor expects the TypeVar to resolve to one of its constraints. The no-matching-overload error for re.compile occurs because _T (which could be str or bytes) doesn't match re.compile's overloads that expect concrete types. These are genuine type-level violations that pyrefly is now correctly catching per the typing spec.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs now enforces that constrained TypeVars resolve to their exact constraint types rather than subtypes. This stricter constraint resolution is causing the new errors.

dd-trace-py (-2)

The removed errors were false positives caused by incorrect type inference. Looking at the code: parts = [p for p in path.split('/')] creates a list[str] since path is str (from match.groups() which returns tuple[str, ...]). Therefore parts.pop() returns str, not str | Unknown. The re.Pattern.match() method accepts str arguments, so there should be no overload error. The PR's constraint promotion improvements fixed the type inference that was incorrectly introducing Unknown into the union type, eliminating these false positive overload resolution failures.
Attribution: The change to constraint promotion logic in find_matching_constraint() and the TypeVar solving arms in pyrefly/lib/solver/solver.rs improved type inference for constrained TypeVars. This fixed the spurious Unknown inference that was causing the false positive overload errors.

streamlit (-1)

This removal is an improvement. The error was a false positive caused by incorrect type inference. The code passes self.get_ws_url("/_stcore/stream") to tornado.websocket.websocket_connect(), where get_ws_url() clearly returns a string URL (constructed via urllib.parse.urlunparse(tuple(parts))). Pyrefly was incorrectly inferring this as Literal[b''] (empty bytes), but the actual type is str. The constraint promotion fix in the TypeVar solver resolved this inference issue, correctly eliminating the false positive. Per the typing spec on constrained TypeVars, the solver should resolve to proper constraint types rather than incorrect subtypes or literals.
Attribution: The change to constraint promotion logic in find_matching_constraint() and the TypeVar solving arms in pyrefly/lib/solver/solver.rs fixed the type inference. The old solver was incorrectly pinning TypeVars to raw argument types (including incorrect inferences like Literal[b'']), while the new logic promotes to the proper constraint type, which resolved the false inference of bytes where a string was expected.

cloud-init (+1, -19)

This is an improvement. The PR correctly implements the typing spec requirement that constrained TypeVars resolve to constraint types rather than subtypes. The single new error correctly identifies a real bug where bool is treated as having a .get() method (line 554 in url_helper.py: matched_headers = [k for k in headers_redact if v.get(k)] where v can be a boolean). The 19 removed errors were false positives caused by inference failures - they contained nonsensical types like Literal[b''] and Unknown that indicated the type checker was confused rather than catching real bugs. Per the typing spec, pyrefly is now correctly promoting bool to int in constrained contexts, which fixed the downstream inference cascade that was producing the spurious errors.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs fixed TypeVar resolution to properly promote subtypes to their matching constraints. This eliminated the cascade of inference errors that were producing 'Unknown' and 'Literal[b'']' types throughout the codebase.

discord.py (+3)

These are genuine bad-override errors where child classes have inconsistent return type annotations compared to their parents. Looking at the inheritance hierarchy: LiteralTransformer extends IdentityTransformer, EnumValueTransformer extends Transformer, and EnumNameTransformer extends Transformer. The parent Transformer.choices property (line 291) returns Optional[List[Choice[Union[int, float, str]]]], but all three child classes override it to return just List[Choice[...]] without the Optional wrapper (lines 411, 462, 489). This violates the Liskov Substitution Principle - code expecting the parent's Optional return type could receive None, but the child implementations guarantee a non-None list. The PR's constraint promotion changes made pyrefly's type resolution more precise, which exposed these pre-existing type inconsistencies that were previously masked by looser TypeVar resolution.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. The new constraint promotion behavior is now correctly enforcing that constrained TypeVars resolve to their constraint types rather than subtypes. This stricter type resolution exposed existing bad-override issues in the discord.py transformer classes that were previously masked.

setuptools (+5, -2)

bad-specialization: These correctly identify constraint violations where AnyStr cannot be resolved to a single constraint type (str or bytes) in the given context. The typing spec requires constrained TypeVars to resolve to exactly one constraint.
no-matching-overload (removed): These were false positives caused by incorrect TypeVar resolution. With proper constraint promotion, AnyStr resolves correctly and the overload calls succeed.

Overall: This is an improvement. The PR implements proper constraint promotion for TypeVars per the typing spec. The new bad-specialization errors correctly catch cases where AnyStr (constrained to str | bytes) is being used in contexts expecting only one constraint type. For example, in os.walk(dir) where dir: GenericPath[AnyStr], the AnyStr must resolve to either str or bytes, but os.walk expects a concrete path type. The removed no-matching-overload errors were false positives caused by incorrect TypeVar resolution - the constraint promotion fix allows glob2 calls with properly resolved AnyStr types to succeed. The net effect is more accurate type checking that catches real constraint violations while eliminating spurious overload failures.

Attribution: The change to find_matching_constraint() and the constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. The new logic promotes subtypes like bool to their matching constraints (e.g., int), which fixes TypeVar resolution but creates new specialization errors when the promoted type doesn't match the constraint bounds.

mitmproxy (+19)

These are genuine type errors being correctly caught by pyrefly's improved constraint handling. The _Rex class compiles regex patterns as binary (bytes) when is_binary=True (line 186-187), so self.re is a re.Pattern[bytes]. However, the code calls self.re.search(bytes(f.request.headers)) where the argument is bytes, but the AnyStr constraint system now correctly identifies that this should resolve to the bytes constraint, not remain as a generic AnyStr. The no-matching-overload errors occur because pyrefly now properly constrains AnyStr to specific types (bytes or str) rather than leaving it generic, and the overload resolution is more precise. The bad-specialization errors indicate that AnyStr is being constrained correctly but some usage patterns don't match the resolved constraint type. This represents improved spec compliance per the typing spec on constrained TypeVars.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. The new constraint promotion system now correctly promotes subtypes to their matching constraints for constrained TypeVars, which exposed that AnyStr (constrained to bytes | str) was not being handled properly in the re.Pattern.search() overloads.

pyinstrument (+1)

This is an improvement. The error correctly identifies a violation of the typing spec for constrained TypeVars. Looking at the code, AnyStr is defined as TypeVar('AnyStr', str, bytes) - a constrained TypeVar that must resolve to either str or bytes, never both simultaneously. The function file_is_a_tty has parameter file_obj: IO[AnyStr] and calls file_is_a_tty(file_obj) on line 65. Since AnyStr appears in both the parameter and the call, the type checker must unify them to the same concrete type (either str or bytes). However, the current usage pattern doesn't provide enough context to determine which constraint AnyStr should resolve to, creating an ambiguous specialization. Per the typing spec on constrained TypeVars, this is exactly the kind of error that should be caught - the TypeVar cannot be properly specialized to a single constraint type.
Attribution: The change to find_matching_constraint() and the constraint promotion logic in pyrefly/lib/solver/solver.rs caused this error. Specifically, the new code in the Variable::Quantified and Variable::PartialQuantified branches now promotes constrained TypeVars to their matching constraint types instead of allowing subtypes to leak through.

parso (+3)

These are genuine bugs in the parso code. The re.match() method can return None when no match is found, but the code immediately calls .group() and .end() methods without checking for None first. This would cause AttributeError at runtime if the regex fails to match. Pyrefly's improved type inference is now correctly catching this unsafe pattern that could crash the program.
Attribution: The constraint promotion changes in find_matching_constraint() and the TypeVar solving logic in pyrefly/lib/solver/solver.rs appear to have made type inference more precise, causing pyrefly to correctly infer that re.match() can return None | Match[str] rather than just Match[str].

aioredis (+2)

This is an improvement. The PR implements constraint promotion for constrained TypeVars per the typing spec. The new errors correctly identify real type violations in aioredis where AnyKeyT = TypeVar('AnyKeyT', bytes, str, memoryview) is being used incorrectly. Looking at the error locations (lines 3138 and 3417), these are in _zaggregate() method calls where the TypeVar constraint system is now properly enforcing that the key types must be one of the specified constraints. Previously, pyrefly was allowing subtype relationships that violated the constraint semantics, but now it correctly promotes to the constraint type and catches when the constraints aren't satisfied. The conformance test improvements (reducing differences from 43 to 42) confirm this is moving toward better spec compliance.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. The solver now promotes constrained TypeVar arguments to their matching constraint types instead of keeping the raw argument type, which exposes type mismatches that were previously hidden.

static-frame (+34, -1)

This is an improvement. The PR implements constraint promotion for constrained TypeVars as required by the typing spec. The new errors correctly identify when constrained TypeVars (TVContainer_co) are being specialized with types that don't match their constraints. For example, in static_frame, TVContainer_co has an upper bound constraint, and the new errors flag when Self@Index (which doesn't match the constraint) is passed where the constrained type is expected. The removed bad-assignment error was a false positive from incorrect type inference during dependency cycle resolution. The new behavior aligns with mypy/pyright and follows the typing spec requirement that constrained TypeVars resolve to their constraint types, not subtypes.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs in the solve_var_subset_cases() method. When encountering a constrained TypeVar, the solver now searches for the narrowest constraint the argument is assignable to and pins the TypeVar to that constraint instead of the raw argument type.

prefect (+7, -4)

This is an improvement. The PR implements correct constrained TypeVar behavior per the typing spec. The new inconsistent-overload errors correctly identify that the overload signature uses Literal[True] for remove_notset while the implementation uses bool - this is a genuine type inconsistency. The removed errors were false positives caused by pyrefly's previous incorrect behavior of resolving constrained TypeVars to subtypes instead of promoting them to constraint types. The new bad-argument-type errors correctly identify that list[Any] | type[NotSet] is not assignable to list[dict[str, Any]] - these are real type mismatches that were previously masked by the incorrect TypeVar resolution.
Attribution: The change to constraint promotion logic in pyrefly/lib/solver/solver.rs in the find_matching_constraint() method and the TypeVar solving arms caused these errors to change. The solver now promotes constrained TypeVar arguments to their matching constraint types instead of pinning them to the raw argument type.

pip (-1)

This is an improvement. The removed error was a false positive - pyrefly was incorrectly inferring that urllib.parse.urlunsplit() returns Literal[b''] when it actually returns str. The new constrained TypeVar promotion logic fixed this inference issue, correctly determining that str is assignable to the declared return type str | None. The code was always correct; pyrefly's inference was wrong before.
Attribution: The constraint promotion changes in find_matching_constraint() and the TypeVar solving logic in pyrefly/lib/solver/solver.rs improved type inference accuracy, fixing the incorrect inference of Literal[b''] for urllib.parse.urlunsplit()

jax (+4)

This is an improvement. The PR implements proper constraint promotion for constrained TypeVars per the typing spec. The new errors correctly catch type violations where bytes (which doesn't match any constraint of int|str) is passed to a constrained TypeVar function. The removed errors were false positives - pyrefly was incorrectly failing assert_type checks and incorrectly allowing constraint violations. Now pyrefly correctly promotes MyStr to str and enforces that all arguments resolve to the same constraint type, which is the correct behavior according to the typing specification.
Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs in the Subset implementation now correctly promotes subtypes like MyStr to their matching constraint type str, and enforces that all arguments to a constrained TypeVar function resolve to the same constraint type.

kopf (-3)

These removed errors were false positives. The fnmatch.fnmatch function signature is fnmatch(name: AnyStr, pat: AnyStr) -> bool where both parameters should be the same string type. In the code, name is NamespaceName (which is NewType('NamespaceName', str)), so pat should be str. However, pyrefly was incorrectly requiring pat to be NamespaceName type, causing false errors when passing regular str values from globs[0], glob.lstrip('!'), and glob. The PR's improvements to constrained TypeVar resolution fixed this type inference issue, correctly allowing str arguments for the pattern parameter.
Attribution: The change to constraint promotion logic in find_matching_constraint() and the TypeVar solving arms in pyrefly/lib/solver/solver.rs fixed the type inference for constrained TypeVars. This improved the solver's ability to correctly resolve types in generic contexts, which eliminated the false positive errors where str was incorrectly considered incompatible with NamespaceName in the fnmatch.fnmatch calls.

anyio (+3)

These are genuine type system improvements. The PR implements proper constraint promotion for constrained TypeVars per the typing spec. The errors indicate that AnyStr (which is constrained to bytes | str) cannot be properly specialized in these contexts. Looking at the code:

  1. Line 201 in _fileio.py: return AsyncFile(file) where file: IO[AnyStr] and AsyncFile expects IO[AnyStr], but the constraint resolution is failing
  2. Lines 108 and 208 in _tempfile.py: Similar pattern with AsyncFile(fp) where fp comes from tempfile functions

The issue appears to be that AnyStr as a type parameter cannot be resolved to a concrete constraint (bytes or str) in these generic contexts. This is a legitimate type system issue - the functions are trying to use AnyStr in a way that doesn't allow the type checker to determine whether it should be bytes or str. The old behavior was incorrectly allowing this ambiguity, while the new constraint promotion correctly identifies it as a specialization error.

Attribution: The change to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. Specifically, the new constraint promotion mechanism in the TypeVar solving arms now correctly promotes subtypes to their matching constraint types, which exposed these AnyStr specialization issues where the type system couldn't resolve the constraint properly.

scrapy (+31, -1)

bad-specialization: AnyStr TypeVar not resolving to its constraints (str/bytes) - spec-compliant enforcement
bad-argument-type: Unresolved AnyStr being passed where specific str/bytes expected
bad-override: Method signatures using AnyStr inconsistent with parent class expectations
unsupported-operation: Type checker now sees certain operations as invalid due to stricter AnyStr handling

Overall: The new errors correctly identify type annotation issues where AnyStr (a constrained TypeVar) is used improperly - it should resolve to either str or bytes, not remain as the generic AnyStr type. Per the typing spec (https://typing.readthedocs.io/en/latest/spec/generics.html#type-variables), this enforcement is required. The scrapy code needs to be more precise about whether it expects str or bytes in specific contexts. The removed error was a false positive about dictionary assignment that was correctly eliminated.

Attribution: The change to constraint promotion logic in find_matching_constraint() and the TypeVar solving arms in pyrefly/lib/solver/solver.rs now enforces that constrained TypeVars like AnyStr resolve to their constraint types (str/bytes) rather than remaining as unresolved AnyStr, causing the scrapy project's loose AnyStr usage to trigger specialization errors.

meson (+6, -1)

This is an IMPROVEMENT. The PR correctly implements constraint promotion per the typing spec (https://typing.readthedocs.io/en/latest/spec/generics.html#constrained-type-variables). The new errors are catching real type violations in the meson codebase where TV_TokenTypes is constrained to (int, str, bool) but the code is passing broader union types like BaseNode | Path | bool | int | str. The constraint promotion correctly identifies that these unions don't match the specific constraint requirements. The removed error appears to be an unrelated inference improvement. Pyrefly is now more spec-compliant and catching genuine type issues that were previously missed.
Attribution: The changes to find_matching_constraint() and constraint promotion logic in pyrefly/lib/solver/solver.rs caused these errors. Specifically, the new constraint promotion in the TypeVar solving arms now enforces that constrained TypeVars resolve to their exact constraint types rather than accepting subtypes or unions.

altair (+4, -1)

TypeVar constraint enforcement: New errors correctly enforce that constrained TypeVars resolve to constraint types, not subtypes, per typing spec requirements

Overall: The new errors are improvements. Pyrefly is now correctly enforcing TypeVar constraint promotion per the typing spec - when a constrained TypeVar like _C = TypeVar('_C', _Conditions, _Condition) is used, the argument type must be promoted to match exactly one of the constraint types, not remain as a subtype. The errors on lines 1015 and 1097 correctly identify that _ConditionExtra and _ConditionClosed don't match the upper bound list[_ConditionClosed] | _ConditionExtra exactly. The removed redundant cast warning is also an improvement as it removes noise.

Attribution: The changes to constraint promotion logic in pyrefly/lib/solver/solver.rs (specifically the find_matching_constraint() method and its usage in TypeVar solving) caused pyrefly to be more strict about TypeVar constraint satisfaction, leading to the new no-matching-overload and bad-specialization errors.

Suggested Fix

Summary: The PR implements constraint promotion for TypeVars per the typing spec, causing 9 regressions where the new logic is too strict for valid code patterns.

1. In find_matching_constraint() in pyrefly/lib/solver/solver.rs, add a guard for AnyStr usage in method signatures: when a constrained TypeVar appears in both parameter and return types of the same method, skip constraint promotion and allow the TypeVar to remain generic. This preserves the existing behavior for recursive method calls with AnyStr.

Files: pyrefly/lib/solver/solver.rs
Confidence: high
Affected projects: trio, schema_salad, cibuildwheel
Fixes: bad-assignment, bad-specialization
Multiple projects (trio, schema_salad, cibuildwheel) have regressions where AnyStr is used consistently in method signatures but constraint promotion breaks recursive calls. The typing spec allows AnyStr to remain generic within a single method scope. Expected outcome: eliminates 4 bad-specialization and bad-assignment errors across trio, schema_salad, and cibuildwheel.

2. In the Variable::Quantified and Variable::PartialQuantified branches in solve_var_subset_cases() in pyrefly/lib/solver/solver.rs, add a check to distinguish bounded TypeVars from constrained TypeVars: only apply constraint promotion when restriction is Restriction::Constraints, not when it's a bound type. For bounded TypeVars, preserve the existing behavior of pinning to the argument type.

Files: pyrefly/lib/solver/solver.rs
Confidence: high
Affected projects: materialize
Fixes: bad-assignment
The materialize project has a regression where a bounded TypeVar (T bound by int | float) is incorrectly treated as constrained. Bounded TypeVars should accept subtypes, not promote to constraints. Expected outcome: eliminates 1 bad-assignment error in materialize.

3. In find_matching_constraint() in pyrefly/lib/solver/solver.rs, add special handling for numpy array types: when checking constraint compatibility for numpy.ndarray and related array types, use a more permissive subtyping check that accounts for numpy's broadcasting and array compatibility rules.

Files: pyrefly/lib/solver/solver.rs
Confidence: medium
Affected projects: colour
Fixes: bad-argument-type
The colour project has regressions where numpy array types are not properly handled by the new constraint promotion logic. Numpy arrays have complex subtyping relationships that need special consideration. Expected outcome: eliminates 2 bad-argument-type errors in colour.

4. In solve_var_subset_cases() in pyrefly/lib/solver/solver.rs, add a guard for overload resolution contexts: when constraint promotion would cause overload resolution failures for well-established patterns (like shutil.copyfileobj with binary streams), preserve the original TypeVar binding rather than promoting to constraints.

Files: pyrefly/lib/solver/solver.rs
Confidence: medium
Affected projects: core, pydantic, hydpy
Fixes: no-matching-overload, bad-argument-type
Projects like core, pydantic, and hydpy have regressions where constraint promotion breaks valid overload patterns. These are mature codebases with working patterns that shouldn't be flagged. Expected outcome: eliminates 9 no-matching-overload and bad-argument-type errors across core, pydantic, and hydpy.


Was this helpful? React with 👍 or 👎

Classification by primer-classifier (31 LLM)

Copy link
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.

Review automatically exported from Phabricator review in Meta.

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.

3 participants