Skip to content

fix bug: generic ABC is mistakenly allowed to be instantiated by providing a type argument to the constructor #4263 - #4283

Open
asukaminato0721 wants to merge 4 commits into
meta:mainfrom
asukaminato0721:4263
Open

asukaminato0721 wants to merge 4 commits into
meta:mainfrom
asukaminato0721:4263

Conversation

@asukaminato0721

@asukaminato0721 asukaminato0721 commented Jul 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes #4263

Preserves direct-class provenance for GenericABC[int](), rejects direct specialized abstract/protocol construction.

Keeps type[GenericABC[int]] calls valid because they may reference concrete subclasses.

Test Plan

add test

@github-actions

This comment has been minimized.

@asukaminato0721

Copy link
Copy Markdown
Collaborator Author

wow

steam.ID uses ABCMeta, but without @abstractmethod.

@github-actions github-actions Bot added size/m and removed size/m labels Jul 24, 2026
@github-actions

This comment has been minimized.

@meta-codesync

meta-codesync Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

This comment has been minimized.

@samwgoldman samwgoldman left a comment

Copy link
Copy Markdown
Member

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.

@samwgoldman samwgoldman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The underlying problem here is that Pyrefly represents two things the same way, but we want different behavior for them

class C[T]:
  ...
X = C[int] # X is `Type::Type(ClassType(...))`
Y: type[C[int]] = C # Y is `Type::Type(ClassType(...))`

This commit works around this by adding a direct_class_specialization bool, but this fixes the problem in a quite limited way. A simple indirection can also work around the missing error:

Ctor = Shape[int]
Ctor()  # still accepted

I think we should first improve the representation of specialized class types so we can distinguish between expressions with the annotation type[C[int]] and the type of the expression C[int]. Then, I think this fix becomes trivial.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@rchen152 rchen152 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, this is really close!

Comment thread crates/pyrefly_types/src/display.rs Resolved
Comment thread pyrefly/lib/test/abstract_methods.rs Resolved
@github-actions

github-actions Bot commented Nov 6, 2026

Copy link
Copy Markdown

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

============================================================
SUMMARY
============================================================
Total: +31 new errors, -30 fixed errors
By preset: +23/-15 (default), +24/-15 (strict)

Projects with changes (13):
  packaging: +1 -1
  artigraph: +0 -1
  prefect: +1 -1
  spark: +2 -2
  pyochain: +2 -0
  colour: +12 -9
  comtypes: +3 -5
  strawberry: +1 -3
  pandera: +2 -3
  steam.py: +3 -2
  static-frame: +3 -0
  antidote: +0 -1
  xarray: +1 -2
============================================================

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

packaging (https://github.com/pypa/packaging)
- ERROR src/packaging/_parser.py:92:31-72: Expected a type form, got instance of `GenericAlias | UnionType | Any` [not-a-type]
+ ERROR src/packaging/_parser.py:92:31-72: Expected a type form, got instance of `GenericAlias | UnionType | type[Literal['and', 'or'] | Sequence[Unknown]] | Any` [not-a-type]

artigraph (https://github.com/artigraph/artigraph)
- ERROR src/arti/types/__init__.py:378:61-72: Object of class `object` has no attribute `key` [missing-attribute]

prefect (https://github.com/PrefectHQ/prefect)
- ERROR src/prefect/logging/filters.py:59:20-35: Class `tuple` has no class attribute `_make` [missing-attribute]
+ ERROR src/prefect/logging/filters.py:59:20-35: Object of type `type[tuple] | type[list[Unknown] | set[Unknown]]` has no attribute `_make` [missing-attribute]

spark (https://github.com/apache/spark)
- ERROR python/pyspark/ml/util.py:756:16-48: Returning Any from function declared to return "RL" [no-any-return-explicit]
+ ERROR python/pyspark/ml/util.py:756:16-48: Returning implicit Any from function declared to return "RL" [no-any-return-implicit]
- ERROR python/pyspark/ml/util.py:756:28-38: The type of attribute `_from_java` is an explicit `Any` [explicit-any-use]
+ ERROR python/pyspark/ml/util.py:756:28-38: The type of attribute `_from_java` is unknown; it is inferred as an implicit `Any` [unknown-attribute-access]

pyochain (https://github.com/OutSquareCapital/pyochain)
+ ERROR benchmarks/test_sorted/_utils.py:122:9-39: Unused `# pyrefly: ignore` comment for code(s): bad-return [unused-ignore]
+ ERROR benchmarks/test_sorted/_utils.py:123:16-23: Class `SortedList` has no class attribute `add` [missing-attribute]

colour (https://github.com/colour-science/colour)
- ERROR colour/continuous/multi_signals.py:413:22-41: Class `float64` has no class attribute `__args__` [missing-attribute]
- ERROR colour/continuous/multi_signals.py:414:60-79: Class `float64` has no class attribute `__args__` [missing-attribute]
+ ERROR colour/continuous/multi_signals.py:413:22-41: Object of type `TypeAlias[DTypeFloat, type[float64 | floating[_16Bit] | floating[_32Bit]]]` has no attribute `__args__` [missing-attribute]
+ ERROR colour/continuous/multi_signals.py:414:60-79: Object of type `TypeAlias[DTypeFloat, type[float64 | floating[_16Bit] | floating[_32Bit]]]` has no attribute `__args__` [missing-attribute]
- ERROR colour/continuous/signal.py:309:22-41: Class `float64` has no class attribute `__args__` [missing-attribute]
- ERROR colour/continuous/signal.py:310:60-79: Class `float64` has no class attribute `__args__` [missing-attribute]
+ ERROR colour/continuous/signal.py:309:22-41: Object of type `TypeAlias[DTypeFloat, type[float64 | floating[_16Bit] | floating[_32Bit]]]` has no attribute `__args__` [missing-attribute]
+ ERROR colour/continuous/signal.py:310:60-79: Object of type `TypeAlias[DTypeFloat, type[float64 | floating[_16Bit] | floating[_32Bit]]]` has no attribute `__args__` [missing-attribute]
- ERROR colour/utilities/array.py:3162:53-72: Class `float64` has no class attribute `__args__` [missing-attribute]
- ERROR colour/utilities/array.py:3166:53-74: Class `complex128` has no class attribute `__args__` [missing-attribute]
+ ERROR colour/utilities/array.py:3158:53-70: Object of type `TypeAlias[DTypeInt, type[signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | signedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit] | unsignedinteger[_8Bit]]]` has no attribute `__args__` [missing-attribute]
+ ERROR colour/utilities/array.py:3162:53-72: Object of type `TypeAlias[DTypeFloat, type[float64 | floating[_16Bit] | floating[_32Bit]]]` has no attribute `__args__` [missing-attribute]
+ ERROR colour/utilities/array.py:3166:53-74: Object of type `TypeAlias[DTypeComplex, type[complex128 | complexfloating[_32Bit, _32Bit]]]` has no attribute `__args__` [missing-attribute]
+ ERROR colour/utilities/array.py:3373:21-38: Object of type `TypeAlias[DTypeInt, type[signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | signedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit] | unsignedinteger[_8Bit]]]` has no attribute `__args__` [missing-attribute]
- ERROR colour/utilities/array.py:3432:21-40: Class `float64` has no class attribute `__args__` [missing-attribute]
+ ERROR colour/utilities/array.py:3432:21-40: Object of type `TypeAlias[DTypeFloat, type[float64 | floating[_16Bit] | floating[_32Bit]]]` has no attribute `__args__` [missing-attribute]
+ ERROR colour/utilities/array.py:3483:21-38: Object of type `TypeAlias[DTypeInt, type[signedinteger[_16Bit] | signedinteger[_32Bit] | signedinteger[_64Bit] | signedinteger[_8Bit] | unsignedinteger[_16Bit] | unsignedinteger[_32Bit] | unsignedinteger[_64Bit] | unsignedinteger[_8Bit]]]` has no attribute `__args__` [missing-attribute]
- ERROR colour/utilities/array.py:3531:21-40: Class `float64` has no class attribute `__args__` [missing-attribute]
+ ERROR colour/utilities/array.py:3531:21-40: Object of type `TypeAlias[DTypeFloat, type[float64 | floating[_16Bit] | floating[_32Bit]]]` has no attribute `__args__` [missing-attribute]
- ERROR colour/utilities/array.py:3664:21-42: Class `complex128` has no class attribute `__args__` [missing-attribute]
+ ERROR colour/utilities/array.py:3664:21-42: Object of type `TypeAlias[DTypeComplex, type[complex128 | complexfloating[_32Bit, _32Bit]]]` has no attribute `__args__` [missing-attribute]

comtypes (https://github.com/enthought/comtypes)
+ ERROR comtypes/safearray.py:106:29-43: Class `_Pointer` has no class attribute `_iid_` [missing-attribute]
+ ERROR comtypes/safearray.py:109:29-43: Class `_Pointer` has no class attribute `_iid_` [missing-attribute]
- ERROR comtypes/safearray.py:106:29-43: The type of this argument is an explicit `Any` [explicit-any-use]
- ERROR comtypes/safearray.py:106:38-43: The type of attribute `_iid_` is an explicit `Any` [explicit-any-use]
- ERROR comtypes/safearray.py:109:29-43: The type of this argument is an explicit `Any` [explicit-any-use]
- ERROR comtypes/safearray.py:109:38-43: The type of attribute `_iid_` is an explicit `Any` [explicit-any-use]
- ERROR comtypes/test/test_basic.py:88:27-41: The type of attribute `QueryInterface` is an explicit `Any` [explicit-any-use]
+ ERROR comtypes/test/test_basic.py:88:9-41: Class `_Pointer` has no class attribute `QueryInterface` [missing-attribute]

strawberry (https://github.com/strawberry-graphql/strawberry)
- ERROR strawberry/schema/name_converter.py:176:41-55: Unused `# type: ignore` comment [unused-type-ignore]
- ERROR strawberry/schema/name_converter.py:177:59-64: Argument `tuple[Any, ...]` is not assignable to parameter `types` with type `list[StrawberryType | type[Any]]` in function `NameConverter.from_generic` [bad-argument-type]
- ERROR strawberry/schema/name_converter.py:177:59-64: The type of this argument is partially unknown; it contains an implicit `Any` [partially-unknown-type]
+ ERROR strawberry/schema/name_converter.py:177:59-64: The type of this argument is unknown because it comes from an error [unknown-from-error]

pandera (https://github.com/pandera-dev/pandera)
+ ERROR pandera/engines/pandas_engine.py:1576:29-1578:26: The type of `failure_cases` is unknown because it comes from an error [unknown-from-error]
+ ERROR pandera/engines/pandas_engine.py:1583:21-34: The type of this argument is unknown because it comes from an error [unknown-from-error]
- ERROR pandera/engines/pandas_engine.py:1569:58-72: Unused `# type: ignore` comment [unused-type-ignore]
- ERROR pandera/engines/pandas_engine.py:1570:13-50: The type of this argument is partially unknown; it contains an implicit `Any` [partially-unknown-type]
- ERROR pandera/engines/pandas_engine.py:1575:12-45: Implicit conversion of `numpy.bool | Any` to `bool` is not allowed [implicit-bool]

steam.py (https://github.com/Gobot1234/steam.py)
+ ERROR steam/ext/csgo/client.py:97:45-83: Cannot instantiate `ID` because it directly extends `ABC` or uses `ABCMeta` [direct-abstract-base-instantiation]
+ ERROR steam/id.py:566:55-77: Cannot instantiate `ID` because it directly extends `ABC` or uses `ABCMeta` [direct-abstract-base-instantiation]
+ ERROR steam/id.py:569:46-71: Cannot instantiate `ID` because it directly extends `ABC` or uses `ABCMeta` [direct-abstract-base-instantiation]
- ERROR steam/trade.py:184:34-41: The type of attribute `__new__` is partially unknown; it contains an implicit `Any` [partially-unknown-type]
- ERROR steam/trade.py:184:41-75: `Inventory` is not assignable to upper bound `GenericAlias` of type variable `Self@GenericAlias` [bad-specialization]

static-frame (https://github.com/static-frame/static-frame)
+ ERROR static_frame/core/interface.py:1056:22-46: Class `Mapping` has no class attribute `_INTERFACE` [missing-attribute]
+ ERROR static_frame/core/interface.py:1057:51-56: The type of this argument is unknown because it comes from an error [unknown-from-error]
+ ERROR static_frame/core/interface.py:1073:25-44: The type of this argument is unknown because it comes from an error [unknown-from-error]

antidote (https://github.com/Finistere/antidote)
-  WARN tests/lib/interface/test_custom.py:300:15-97: Redundant cast: `type[test_event_subscriber_example.EventSubscriber[test_event_subscriber_example.InitializationEvent]]` is the same type as `type[test_event_subscriber_example.EventSubscriber[test_event_subscriber_example.InitializationEvent]]` [redundant-cast]

xarray (https://github.com/pydata/xarray)
- ERROR xarray/tests/test_concat.py:207:9-213:10: The type of this argument is an explicit `Any` [explicit-any-use]
+ ERROR xarray/tests/test_concat.py:208:12-60: Object of type `type[arrayapi[Any, Any] | arrayfunction[Any, Any] | ndarray]` has no attribute `_concat_same_type` [missing-attribute]
- ERROR xarray/tests/test_concat.py:208:43-60: The type of attribute `_concat_same_type` is an explicit `Any` [explicit-any-use]

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.

bug: generic ABC is mistakenly allowed to be instantiated by providing a type argument to the constructor

3 participants