Skip to content

fix deprecated - false negative when dectorated function has a decorator that changes its type to a union #5298 - #5339

Open
asukaminato0721 wants to merge 2 commits into
meta:mainfrom
asukaminato0721:5298
Open

asukaminato0721 wants to merge 2 commits into
meta:mainfrom
asukaminato0721:5298

Conversation

@asukaminato0721

@asukaminato0721 asukaminato0721 commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes #5298

now preserves deprecation metadata across callable unions and reports warnings for calls and references.

  • I am a human, and I fully understand the code I am submitting.

Test Plan

add test

@meta-codesync

meta-codesync Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

This comment has been minimized.

@stroxler stroxler 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! It looks pretty good to me.

AI review flagged a couple of regressions that frankly I don't think I would have caught:

1. Callback-protocol deprecation gets erased

[function.rs:1920–1922](https://github.com/meta/pyrefly/blob/4252c5bc3654815ab005185803b014cb7e701fc0/pyrefly/lib/alt/function.rs#L1920-L1922)

The new union recursion sends callback protocols through a conversion that replaces their __call__ flags with the original decorated function’s flags. That loses an existing deprecation:

class P(Protocol):
    @deprecated("Use another callback")
    def __call__(self, x: int) -> int: ...

def dec(fn: Callable[[int], int]) -> P | None: ...

@dec
def f(x: int) -> int: ...

if f is not None:
    f(1)

The parent reports P.__call__ as deprecated; the PR reports nothing.

Suggesion is to preserve the callback’s own deprecation when applying decoratee metadata, and add this regression test.

2. Conditional and or expressions produce duplicate warnings

[expr.rs:1587–1592](https://github.com/meta/pyrefly/blob/4252c5bc3654815ab005185803b014cb7e701fc0/pyrefly/lib/alt/expr.rs#L1587-L1592)

With a deprecated old and non-deprecated new:

g = old if flag else new
h = cb or old

The branch reference already reports deprecation. The new union traversal reports it again on the enclosing expression. The diagnostics have different ranges, so existing deduplication does not merge them.

Each assignment produces one warning on the parent and two on the PR. Avoid re-reporting deprecation on the aggregate expression when its branch has already been diagnosed.

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

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

============================================================
SUMMARY
============================================================
Total: +7 new errors, -2 fixed errors
By preset: +6/-2 (default), +7/-2 (strict)

Projects with changes (4):
  pip: +0 -1
  scikit-learn: +5 -0
  setuptools: +1 -0
  pandera: +1 -1
============================================================

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

pip (https://github.com/pypa/pip)
- ERROR src/pip/_vendor/distlib/compat.py:584:13-21: Class member `ChainMap.__repr__` overrides parent class `MutableMapping` in an inconsistent manner [bad-override-mutable-attribute]

scikit-learn (https://github.com/scikit-learn/scikit-learn)
+ ERROR sklearn/utils/_test_common/instance_generator.py:839:34-43: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/utils/_test_common/instance_generator.py:839:34-43: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/utils/_test_common/instance_generator.py:843:19-28: `sklearn.linear_model._passive_aggressive.PassiveAggressiveClassifier` is deprecated [deprecated]
+ ERROR sklearn/utils/_test_common/instance_generator.py:843:19-28: `sklearn.linear_model._passive_aggressive.PassiveAggressiveRegressor` is deprecated [deprecated]
+ ERROR sklearn/utils/tests/test_testing.py:527:48-49: `MockMetaEstimator.fit` is deprecated [deprecated]

setuptools (https://github.com/pypa/setuptools)
+ ERROR setuptools/_vendor/jaraco/text/__init__.py:126:9-17: Class member `FoldedCase.casefold` overrides a member in a parent class but is missing an `@override` decorator [missing-override-decorator]

pandera (https://github.com/pandera-dev/pandera)
- ERROR pandera/strategies/pandas_strategies.py:1888:51-65: Argument `dict[int | Unknown, Unknown]` is not assignable to parameter `nullable_columns` with type `dict[str, bool]` [bad-argument-type]
+ ERROR pandera/strategies/pandas_strategies.py:1888:51-65: Argument `dict[int | Unknown, Unknown]` is not assignable to parameter `nullable_columns` with type `dict[str, bool]` in function `null_dataframe_masks` [bad-argument-type]

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.

deprecated - false negative when dectorated function has a decorator that changes its type to a union

3 participants