Skip to content

infer Self when constructing a class using cls()#2557

Closed
yangdanny97 wants to merge 3 commits intofacebook:mainfrom
yangdanny97:export-D94416719
Closed

infer Self when constructing a class using cls()#2557
yangdanny97 wants to merge 3 commits intofacebook:mainfrom
yangdanny97:export-D94416719

Conversation

@yangdanny97
Copy link
Contributor

Summary: fixes #2528

Differential Revision: D94416719

Summary:
If we're star-unpacking a list/tuple/set literal that only has 1 element, we should consume 1 parameter, not more.

fixes facebook#2467

Differential Revision: D94409371
…args

Summary:
We usually don't know how many parameters a star-unpacked arg consumes, so currently we consume all positional parameters.

However, positional parameters can be passed arguments by name, so this diff makes it s.t. we look ahead at which arguments are passed by name & stop consuming positional parameters if we see one.

The current behavior leads to quite a few false positives, because if you pass any non-kw-only argument by name after a star unpacking it will always give a "duplicate value provided" error.

This is unsound, since the thing being unpacked could be long enough to actually consume all positional params, but we have no way of telling so we sould err on the side of false negatives here IMO.

Ideally we might want some sort of backtracking to figure this out, but for now this fix should reduce false positives.

fixes facebook#2468

Differential Revision: D94411643
Summary: fixes facebook#2528

Differential Revision: D94416719
@meta-cla meta-cla bot added the cla signed label Feb 25, 2026
@meta-codesync
Copy link

meta-codesync bot commented Feb 25, 2026

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

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.

@github-actions
Copy link

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

trio (https://github.com/python-trio/trio)
- ERROR src/trio/_tests/test_repl.py:270:18-73: Unpacked argument `tuple[str, ...]` is not assignable to parameter `*args` with type `tuple[StrOrBytesPath, *tuple[StrOrBytesPath, ...]]` in function `os.execlp` [bad-argument-type]
- ERROR src/trio/testing/_raises_group.py:69:16-25: Returned type `_ExceptionInfo[BaseException]` is not assignable to declared return type `_ExceptionInfo[MatchE]` [bad-return]
+ ERROR src/trio/testing/_raises_group.py:69:16-25: Returned type `Self@_ExceptionInfo` is not assignable to declared return type `_ExceptionInfo[MatchE]` [bad-return]

hydpy (https://github.com/hydpy-dev/hydpy)
- ERROR hydpy/core/testtools.py:1348:14-33: Cannot use `TestIO` as a context manager [bad-context-manager]
+ ERROR hydpy/core/testtools.py:1348:14-33: Cannot use `Self@TestIO` as a context manager [bad-context-manager]

apprise (https://github.com/caronc/apprise)
- ERROR apprise/plugins/telegram.py:433:69-80: Multiple values for argument `fmt` in function `apprise.utils.parse.validate_regex` [bad-keyword-argument]
- ERROR tests/test_api.py:237:18-71: Argument `str` is not assignable to parameter `asset` with type `AppriseAsset | None` in function `apprise.apprise.Apprise.add` [bad-argument-type]

operator (https://github.com/canonical/operator)
- ERROR ops/pebble.py:625:16-636:10: Returned type `ops.pebble.Warning` is not assignable to declared return type `builtins.Warning` [bad-return]
+ ERROR ops/pebble.py:625:16-636:10: Returned type `Self@ops.pebble.Warning` is not assignable to declared return type `builtins.Warning` [bad-return]

pandera (https://github.com/pandera-dev/pandera)
- ERROR pandera/api/checks.py:246:16-252:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:260:16-266:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:280:16-286:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:298:16-304:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:316:16-322:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:334:16-340:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:440:16-449:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:499:16-506:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:555:16-562:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:577:16-584:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:601:16-608:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:618:16-624:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:633:16-639:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:684:20-690:14: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:697:16-705:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/checks.py:723:16-730:10: Returned type `BaseCheck` is not assignable to declared return type `Check` [bad-return]
- ERROR pandera/api/hypotheses.py:282:16-290:10: Returned type `BaseCheck` is not assignable to declared return type `Hypothesis` [bad-return]
- ERROR pandera/api/hypotheses.py:375:16-381:10: Returned type `BaseCheck` is not assignable to declared return type `Hypothesis` [bad-return]

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ERROR tests/debugging/probe/test_remoteconfig.py:104:67-94: Multiple values for argument `status_logger` in function `ProbeRCAdapter.__init__` [bad-keyword-argument]
- ERROR tests/profiling/collector/pprof_utils.py:136:26-58: Multiple values for argument `event_type` in function `LockEvent.__init__` [bad-keyword-argument]
- ERROR tests/profiling/collector/pprof_utils.py:141:26-58: Multiple values for argument `event_type` in function `LockEvent.__init__` [bad-keyword-argument]

vision (https://github.com/pytorch/vision)
- ERROR references/segmentation/train.py:20:54-73: Multiple values for argument `mode` in function `torchvision.datasets.sbd.SBDataset.__init__` [bad-keyword-argument]
- ERROR test/test_backbone_utils.py:107:58-85: Multiple values for argument `tracer_kwargs` in function `torchvision.models.feature_extraction.create_feature_extractor` [bad-keyword-argument]
- ERROR test/test_backbone_utils.py:107:87-113: Multiple values for argument `suppress_diff_warning` in function `torchvision.models.feature_extraction.create_feature_extractor` [bad-keyword-argument]
- ERROR torchvision/models/quantization/googlenet.py:78:20-98: Multiple values for argument `blocks` in function `torchvision.models.googlenet.GoogLeNet.__init__` [bad-keyword-argument]
- ERROR torchvision/models/quantization/inception.py:129:13-137:14: Multiple values for argument `inception_blocks` in function `torchvision.models.inception.Inception3.__init__` [bad-keyword-argument]

discord.py (https://github.com/Rapptz/discord.py)
- ERROR discord/ext/commands/core.py:1552:29-66: No matching overload found for function `command` called with arguments: (*tuple[Any, ...], name=str, cls=type[Command[Any, Ellipsis, Any]], **_CommandDecoratorKwargs) [no-matching-overload]
- ERROR discord/ext/commands/core.py:1609:27-64: No matching overload found for function `group` called with arguments: (*tuple[Any, ...], name=str, cls=type[Group[Any, Ellipsis, Any]], **_GroupDecoratorKwargs) [no-matching-overload]
- ERROR discord/gateway.py:142:48-57: Multiple values for argument `name` in function `threading.Thread.__init__` [bad-keyword-argument]

static-frame (https://github.com/static-frame/static-frame)
- ERROR static_frame/core/frame.py:6911:20-65: Returned type `Frame[Any, Any, *tuple[Any, ...]] | Self@Frame` is not assignable to declared return type `Frame[Any, Any, *tuple[Any, ...]]` [bad-return]
+ ERROR static_frame/core/frame.py:6911:20-65: Returned type `Self@Frame` is not assignable to declared return type `Frame[Any, Any, *tuple[Any, ...]]` [bad-return]
- ERROR static_frame/core/frame.py:7165:20-65: Returned type `Frame[Any, Any, *tuple[Any, ...]] | Self@Frame` is not assignable to declared return type `Frame[Any, Any, *tuple[Any, ...]]` [bad-return]
+ ERROR static_frame/core/frame.py:7165:20-65: Returned type `Self@Frame` is not assignable to declared return type `Frame[Any, Any, *tuple[Any, ...]]` [bad-return]

prefect (https://github.com/PrefectHQ/prefect)
- ERROR src/prefect/_internal/concurrency/services.py:333:60-74: Argument `(self: _QueueServiceBase[Unknown]) -> None` is not assignable to parameter with type `() -> Awaitable[Awaitable[Unknown] | Unknown] | Awaitable[Unknown] | Unknown` in function `prefect._internal.concurrency.api.create_call` [bad-argument-type]
+ ERROR src/prefect/_internal/concurrency/services.py:333:60-74: Argument `(self: Self@_QueueServiceBase) -> None` is not assignable to parameter with type `() -> Awaitable[Awaitable[Unknown] | Unknown] | Awaitable[Unknown] | Unknown` in function `prefect._internal.concurrency.api.create_call` [bad-argument-type]
- ERROR src/prefect/_waiters.py:252:60-74: Argument `(self: FlowRunWaiter) -> None` is not assignable to parameter with type `() -> Awaitable[Awaitable[Unknown] | Unknown] | Awaitable[Unknown] | Unknown` in function `prefect._internal.concurrency.api.create_call` [bad-argument-type]
+ ERROR src/prefect/_waiters.py:252:60-74: Argument `(self: Self@FlowRunWaiter) -> None` is not assignable to parameter with type `() -> Awaitable[Awaitable[Unknown] | Unknown] | Awaitable[Unknown] | Unknown` in function `prefect._internal.concurrency.api.create_call` [bad-argument-type]
- ERROR src/prefect/task_runs.py:267:60-74: Argument `(self: TaskRunWaiter) -> None` is not assignable to parameter with type `() -> Awaitable[Awaitable[Unknown] | Unknown] | Awaitable[Unknown] | Unknown` in function `prefect._internal.concurrency.api.create_call` [bad-argument-type]
+ ERROR src/prefect/task_runs.py:267:60-74: Argument `(self: Self@TaskRunWaiter) -> None` is not assignable to parameter with type `() -> Awaitable[Awaitable[Unknown] | Unknown] | Awaitable[Unknown] | Unknown` in function `prefect._internal.concurrency.api.create_call` [bad-argument-type]
- ERROR src/prefect/workers/base.py:1035:52-65: Argument `BaseJobConfiguration` is not assignable to parameter `configuration` with type `C` in function `BaseWorker._initiate_run` [bad-argument-type]
- ERROR src/prefect/workers/base.py:1037:51-64: Argument `BaseJobConfiguration` is not assignable to parameter `configuration` with type `C` in function `BaseWorker.run` [bad-argument-type]
- ERROR src/prefect/workers/base.py:1592:16-29: Returned type `BaseJobConfiguration` is not assignable to declared return type `C` [bad-return]

pip (https://github.com/pypa/pip)
- ERROR src/pip/_vendor/pkg_resources/__init__.py:3415:18-53: No matching overload found for function `_warnings.warn` called with arguments: (*tuple[Unknown, ...], stacklevel=int, **dict[str, Unknown]) [no-matching-overload]

jax (https://github.com/google/jax)
- ERROR jax/_src/random.py:1411:40-59: Multiple values for argument `log_space` in function `_gamma_one` [bad-keyword-argument]
- ERROR jax/experimental/array_serialization/serialization_test.py:68:43-70: Multiple values for argument `shardings` in function `jax.experimental.array_serialization.pytree_serialization.load` [bad-keyword-argument]
- ERROR jax/experimental/sparse/bcoo.py:1044:78-113: Multiple values for argument `dimension_numbers` in function `jax._src.lax.lax.dot_general` [bad-keyword-argument]

scrapy (https://github.com/scrapy/scrapy)
- ERROR scrapy/core/downloader/contextfactory.py:88:13-26: Multiple values for argument `method` in function `ScrapyClientContextFactory.__init__` [bad-keyword-argument]
- ERROR scrapy/core/downloader/contextfactory.py:89:13-52: Multiple values for argument `tls_verbose_logging` in function `ScrapyClientContextFactory.__init__` [bad-keyword-argument]
- ERROR scrapy/core/downloader/contextfactory.py:90:13-36: Multiple values for argument `tls_ciphers` in function `ScrapyClientContextFactory.__init__` [bad-keyword-argument]

@meta-codesync
Copy link

meta-codesync bot commented Feb 26, 2026

This pull request has been merged in 5684831.

@github-actions
Copy link

Primer Diff Classification

❌ 1 regression(s) | ✅ 9 improvement(s) | ➖ 3 neutral | 13 project(s) total

1 regression(s) across prefect. error kinds: bad-argument-type, bad-return. caused by construct_class(). 9 improvement(s) across trio, apprise, pandera, dd-trace-py, vision, discord.py, pip, jax, scrapy.

Project Verdict Changes Error Kinds Root Cause
trio ✅ Improvement +1, -2 bad-argument-type, bad-return construct_class()
hydpy ➖ Neutral +1, -1 bad-context-manager
apprise ✅ Improvement -2 bad-argument-type, bad-keyword-argument mark_done()
operator ➖ Neutral +1, -1 bad-return
pandera ✅ Improvement -18 bad-return construct_class()
dd-trace-py ✅ Improvement -3 bad-keyword-argument mark_done()
vision ✅ Improvement -5 bad-keyword-argument pyrefly/lib/alt/callable.rs
discord.py ✅ Improvement -3 bad-keyword-argument, no-matching-overload construct_class()
static-frame ➖ Neutral +2, -2 bad-return
prefect ❌ Regression +3, -6 bad-argument-type, bad-return construct_class()
pip ✅ Improvement -1 no-matching-overload pyrefly/lib/alt/callable.rs
jax ✅ Improvement -3 bad-keyword-argument call_infer()
scrapy ✅ Improvement -3 bad-keyword-argument construct_class()
Detailed analysis

❌ Regression (1)

prefect (+3, -6)

The new errors show type inference failures where Self@_QueueServiceBase indicates pyrefly couldn't resolve the type parameter in the Self type. The @_ syntax suggests an internal inference failure. The original code pattern of passing bound methods to create_call() is valid Python that mypy/pyright handle correctly. The change from concrete types like _QueueServiceBase[Unknown] to malformed Self@_ types represents degraded type resolution quality.
Attribution: The change to construct_class() in pyrefly/lib/alt/call.rs that distinguishes ConstructorKind::TypeOfSelf from ConstructorKind::TypeOfClass. When cls() is called where cls has type type[Self], it now returns Self instead of the concrete class type, but the Self type resolution is failing (producing Self@_QueueServiceBase instead of a proper Self type).

✅ Improvement (9)

trio (+1, -2)

The new error shows Self@_ExceptionInfo in the error message, which contains the problematic @_ type indicating a type inference failure. This suggests pyrefly is having trouble resolving the Self type properly in this context. The removed errors were both false positives: (1) os.execlp(*[sys.executable, '-u', '-m', 'trio']) is valid since os.execlp accepts *args: StrOrBytesPath and the unpacked list provides compatible string arguments, and (2) the old _ExceptionInfo[BaseException] vs _ExceptionInfo[MatchE] error was incorrect because cls() in a classmethod should return Self when cls has type type[Self]. The PR correctly implemented this Self behavior but introduced an inference issue shown by the @_ type.
Attribution: The change to construct_class() in pyrefly/lib/alt/call.rs added a ConstructorKind::TypeOfSelf variant that specifically handles type[Self] constructor calls to return Self instead of the base class type. The os.execlp fix likely came from improvements to callable argument checking in pyrefly/lib/alt/callable.rs.

apprise (-2)

Both removed errors were false positives caused by pyrefly's incorrect analysis of starred argument unpacking. The telegram.py error incorrectly claimed duplicate fmt keyword arguments when only one was explicitly provided. The test_api.py error misidentified the parameter type for unpacked string arguments. The PR changes to starred argument handling in callable.rs fixed these analysis bugs, making pyrefly more accurate.
Attribution: The changes to mark_done() and starred argument handling in pyrefly/lib/alt/callable.rs fixed the false positive analysis of unpacked arguments, particularly the logic that was incorrectly inferring parameter assignments and duplicate keyword arguments from starred expressions.

pandera (-18)

These were false positive errors. In classmethods, cls() should return Self (the calling class), not the base class. When Check.equal_to() is called, it returns a Check. When a subclass calls it, it should return an instance of that subclass. Pyrefly was incorrectly inferring the return type as BaseCheck instead of Self, creating invalid type errors. The PR fix correctly distinguishes type[Self] from type[Class] in constructor calls, allowing classmethods to properly return Self types.
Attribution: The changes to construct_class() in pyrefly/lib/alt/call.rs now distinguish between ConstructorKind::TypeOfClass and ConstructorKind::TypeOfSelf, with the latter correctly returning self.heap.mk_self_type(cls) instead of self.heap.mk_class_type(cls). This fixes the inference of cls() calls in classmethods to return Self instead of the concrete base class.

dd-trace-py (-3)

The removed errors were false positives claiming 'multiple values for argument' in valid Python code. Looking at the source:

  1. Line 104: super(SyncProbeRCAdapter, self).__init__(*args, **kwargs, status_logger=status_logger) - This passes *args positionally and adds status_logger as a keyword argument. The parent ProbeRCAdapter.__init__ accepts status_logger as a parameter, so this is valid.

  2. Lines 136/141: super().__init__(event_type=LockEventType.ACQUIRE, *args, **kwargs) - This passes event_type as a keyword argument along with *args and **kwargs. The parent LockEvent.__init__ accepts event_type as its first parameter, so this is valid.

The PR changes improved pyrefly's handling of starred arguments combined with keyword arguments, correctly recognizing that these patterns don't create argument conflicts. The new logic stops consuming positional parameters when it encounters a parameter that has a corresponding keyword argument, preventing the false 'multiple values' errors.

Attribution: The changes to CallArgPreEval handling in pyrefly/lib/alt/callable.rs improved the analysis of starred arguments (*args) combined with keyword arguments. The new mark_done() method and logic to stop consuming positional parameters when a keyword argument is present (lines 610-618) fixed the false positive detection of argument conflicts.

vision (-5)

These were false positive errors. The removed errors flagged common Python patterns for parameter forwarding (using *args/**kwargs with explicit keyword arguments) that work correctly at runtime. The code shows defensive programming practices like kwargs.pop() and conditional parameter setting to handle potential conflicts. The PR diff explicitly acknowledges these were false positive 'multiple values' errors that needed to be prevented. Removing these incorrect errors is an improvement - pyrefly is now less noisy and aligns better with established Python idioms.
Attribution: The change to argument resolution logic in pyrefly/lib/alt/callable.rs (specifically the new logic around lines 607-618) that stops consuming positional parameters when reaching parameters with corresponding keyword arguments. This prevents the false positive 'multiple values' errors.

discord.py (-3)

These removed errors were false positives in pyrefly's overload resolution system. The first two errors incorrectly claimed that calls to command(name=name, cls=cls, *args, **kwargs) and group(name=name, cls=cls, *args, **kwargs) had no matching overload, but examining the function signatures shows these calls should match the available overloads. The third error incorrectly detected a duplicate name keyword argument in a threading.Thread constructor call where name is only passed once. The PR changes improved argument handling and overload resolution, fixing these false positives.
Attribution: The changes to construct_class() in pyrefly/lib/alt/call.rs added a constructor_kind parameter and distinguished between TypeOfClass and TypeOfSelf. The changes to argument handling in pyrefly/lib/alt/callable.rs improved star argument processing and added logic to prevent consuming positional parameters when keyword arguments are present. These changes likely fixed the overload resolution issues that were causing the false positive errors.

pip (-1)

The removed error was a false positive. The code warnings.warn(stacklevel=level + 1, *args, **kw) is valid argument forwarding that should work with warnings.warn's overloads. The PR improved pyrefly's overload resolution for calls involving starred arguments, correctly removing this incorrect error. This is an improvement - pyrefly is now less noisy and more accurate in its overload checking.
Attribution: The changes to argument handling in pyrefly/lib/alt/callable.rs, specifically the improved processing of starred arguments and better overload resolution with keyword arguments, fixed the false positive overload resolution failure

jax (-3)

These were false positive errors. The removed errors claimed 'multiple values for argument' but the code patterns are actually valid:

  1. In jax/_src/random.py:1411, _gamma_one(*args, log_space=log_space) passes log_space as a keyword argument, not positional, so there's no conflict.

  2. In the test file, load(*args, shardings=_DEFAULT_SHARDING, **kw) passes shardings as a keyword argument explicitly.

  3. In bcoo.py, dot_general(..., dimension_numbers=dimension_numbers) passes dimension_numbers as a keyword.

The PR diff shows that pyrefly improved its handling of starred arguments by adding logic to stop consuming positional parameters when reaching one that has a corresponding keyword argument. This prevents false positive 'multiple values' errors for valid code patterns where starred unpacking is used alongside explicit keyword arguments. The change makes pyrefly's behavior align with Python's actual argument resolution rules and with other type checkers like mypy/pyright.

Attribution: The change to callable.rs in the call_infer() function added logic to prevent false positive 'multiple values' errors when using starred arguments with unknown length. Specifically, the code now stops consuming positional parameters when it reaches one that has a corresponding keyword argument, which prevents incorrectly flagging these valid patterns as errors.

scrapy (-3)

These were false positive errors. The from_crawler method correctly passes *args (which binds to the *args parameter in __init__) alongside explicit keyword arguments (method=method, tls_verbose_logging=tls_verbose_logging, tls_ciphers=tls_ciphers) which bind to their respective named parameters. There's no 'multiple values' conflict - the arguments bind to different parameters as intended. The PR diff shows pyrefly improved its argument binding logic to avoid these false positives, with a comment explicitly mentioning this prevents 'false positive multiple values errors'.
Attribution: The change to parameter matching logic in construct_class() and the callable argument handling in pyrefly/lib/alt/callable.rs fixed the false positive detection of 'multiple values' errors when star arguments coexist with keyword arguments.

➖ Neutral (3)

hydpy (+1, -1)

Same errors at same locations with same error kinds — message wording changed, no behavioral impact.

operator (+1, -1)

Same errors at same locations with same error kinds — message wording changed, no behavioral impact.

static-frame (+2, -2)

Same errors at same locations with same error kinds — message wording changed, no behavioral impact.

Suggested Fix

Summary: The PR introduced a regression in Self type resolution where type[Self] constructor calls produce malformed Self@_ types instead of proper Self types.

1. In construct_class() in pyrefly/lib/alt/call.rs, fix the Self type construction logic. When constructor_kind == ConstructorKind::TypeOfSelf, ensure the Self type is properly resolved by checking if the class has valid type arguments before calling self.heap.mk_self_type(cls). Add a fallback to mk_class_type if Self resolution fails to prevent malformed Self@_ types.

Files: pyrefly/lib/alt/call.rs
Confidence: high
Affected projects: prefect
Fixes: bad-assignment
The regression shows Self@QueueServiceBase types which indicates the mk_self_type() call is failing to properly resolve the Self type. The @ syntax suggests an internal inference failure. Adding proper validation and fallback logic would prevent these malformed types while preserving the correct Self semantics for valid cases. Expected outcome: eliminates 3 bad-assignment errors in prefect while maintaining the 9 improvements across other projects.


Classification by primer-classifier (3 heuristic, 10 LLM) · Was this helpful? React with 👍 or 👎

@yangdanny97
Copy link
Contributor Author

@migeed-z this suggested fix is pretty wrong

The @ syntax suggests an internal inference failure

this is not true, the rest of the analysis is based on this mistaken premise

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.

Inferred type of returned cls() is not Self

3 participants