Skip to content

Report redefined instance attributes across methods - #5392

Open
mangeshraut712 wants to merge 12 commits into
meta:mainfrom
mangeshraut712:fix/redef-instance-attr-5387
Open

mangeshraut712 wants to merge 12 commits into
meta:mainfrom
mangeshraut712:fix/redef-instance-attr-5387

Conversation

@mangeshraut712

@mangeshraut712 mangeshraut712 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #5387.

Summary

Emit a redefinition diagnostic when an instance attribute is annotated in more than one method. The binder preserves method-level annotations in source order before field merging.

Test Plan

  • cargo test -p pyrefly test_self_attribute_redefinition_across_methods
  • python3 test.py --no-test --no-tensor-shapes --no-conformance --no-jsonschema --no-extension

Compare per-method annotations in source order before method fields are merged.
@meta-cla meta-cla Bot added the cla signed label Oct 26, 2026
@mangeshraut712 mangeshraut712 changed the title Report duplicate instance attribute annotations across methods Report redefined instance attributes across methods Oct 26, 2026
@meta-codesync

meta-codesync Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

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

@github-actions

This comment has been minimized.

Same as meta#5390: BSD head rejects -n 0; use dd bs=1 count=0.
@github-actions github-actions Bot added size/s and removed size/s labels Oct 26, 2026
@github-actions

This comment has been minimized.

@github-actions github-actions Bot added size/s and removed size/s labels Oct 27, 2026
@github-actions github-actions Bot added size/s and removed size/s labels Oct 27, 2026
@github-actions

This comment has been minimized.

@mangeshraut712

Copy link
Copy Markdown
Contributor Author

CI is green (27 checks). Reports redefined instance attributes across methods. Please review and merge when you can.

@github-actions github-actions Bot added size/s and removed size/s labels Oct 27, 2026
@github-actions

This comment has been minimized.

@github-actions github-actions Bot added size/s and removed size/s labels Oct 27, 2026
@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! This needs a rebase to land

In addition I think there may be a couple of issues worth fixing:

(1) Compatible annotations become errors — class.rs:470–480.

A class declaring x: int, then repeating self.x: int in init and reset, gains a redefinition error. The parent, mypy, Pyright, and ty all accept this case. The check should compare resolved annotations against the effective field declaration rather than reject repeated names unconditionally.

(2) Annotations on another object are attributed to this class — scope.rs:3236–3248.

A staticmethod's other.x: str, where other is another class, can trigger a redefinition of this class's self.x. Shadowed self parameters in nested functions behave similarly. Although reference checkers prohibit these non-self annotations, the new diagnostic still names the wrong field.

@github-actions github-actions Bot added size/s and removed size/s labels Nov 1, 2026
@github-actions github-actions Bot added size/s and removed size/s labels Nov 1, 2026
@github-actions

This comment has been minimized.

…attr-5387

# Conflicts:
#	pyrefly/lib/binding/class.rs
@github-actions github-actions Bot added size/s and removed size/s labels Nov 2, 2026
A repeated self.x annotation is only a redefinition when it differs from the
earlier method annotation. Fields declared in the class body are left to the
existing declaration checks. Staticmethod parameters and names rebound in a
nested scope no longer count as the class receiver.
@mangeshraut712

Copy link
Copy Markdown
Contributor Author

Merged main and pushed bc826b4 for both points.

  1. A repeated self.x: T is only reported when its annotation differs from the earlier method annotation. If the class body declares the field, the existing declaration checks handle it and this check stays quiet, so x: int plus self.x: int in __init__ and reset no longer errors.
  2. Staticmethod parameters are no longer treated as the receiver, and a name rebound in a nested scope (like an inner def f(self): ...) is not attributed to the enclosing method's self. Those cases now only get the existing "Cannot annotate non-self attribute" error.

Added tests for both. The full pyrefly lib test suite passes locally.

@github-actions github-actions Bot added size/m and removed size/s labels Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

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

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

Projects with changes (15):
  tornado: +0 -2
  psycopg: +0 -1
  jax: +0 -1
  spark: +0 -2
  prefect: +0 -1
  freqtrade: +0 -7
  pwndbg: +0 -2
  manticore: +0 -1
  mitmproxy: +0 -4
  cloud-init: +0 -1
  strawberry: +0 -1
  anyio: +0 -2
  hydpy: +0 -4
  meson: +0 -1
  dd-trace-py: +0 -1
============================================================

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

tornado (https://github.com/tornadoweb/tornado)
- ERROR tornado/test/websocket_test.py:1244:12-22: Attribute `drop_pongs` is implicitly defined by assignment in method `install_hook`, which is not a constructor [implicitly-defined-attribute]
- ERROR tornado/test/websocket_test.py:1245:12-26: Attribute `pongs_received` is implicitly defined by assignment in method `install_hook`, which is not a constructor [implicitly-defined-attribute]

psycopg (https://github.com/psycopg/psycopg)
- ERROR psycopg_pool/psycopg_pool/pool.py:569:18-28: Attribute `autocommit` is implicitly defined by assignment in method `check_connection`, which is not a constructor [implicitly-defined-attribute]

jax (https://github.com/google/jax)
- ERROR jax/_src/export/shape_poly_decision.py:110:13-36: Attribute `_decision_initial_state` is implicitly defined by assignment in method `build`, which is not a constructor [implicitly-defined-attribute]

spark (https://github.com/apache/spark)
- ERROR python/pyspark/pandas/internal.py:1193:21-26: Attribute `index` is implicitly defined by assignment in method `restore_index`, which is not a constructor [implicitly-defined-attribute]
- ERROR python/pyspark/pandas/internal.py:1205:17-24: Attribute `columns` is implicitly defined by assignment in method `restore_index`, which is not a constructor [implicitly-defined-attribute]

prefect (https://github.com/PrefectHQ/prefect)
- ERROR src/prefect/workers/_cleanup.py:444:15-31: Attribute `owns_reservation` is implicitly defined by assignment in method `_lose_reservation`, which is not a constructor [implicitly-defined-attribute]

freqtrade (https://github.com/freqtrade/freqtrade)
- ERROR freqtrade/persistence/custom_data.py:95:18-23: Attribute `value` is implicitly defined by assignment in method `_convert_custom_data`, which is not a constructor [implicitly-defined-attribute]
- ERROR freqtrade/persistence/custom_data.py:103:26-51: The type of this attribute is an explicit `Any` [explicit-any-use]
- ERROR freqtrade/resolvers/strategy_resolver.py:136:22-33: Attribute `minimal_roi` is implicitly defined by assignment in method `_normalize_attributes`, which is not a constructor [implicitly-defined-attribute]
- ERROR freqtrade/resolvers/strategy_resolver.py:136:36-141:14: This expression's type is partially unknown; it contains an implicit `Any`. Please provide an explicit type annotation. [partially-unknown-type]
- ERROR freqtrade/resolvers/strategy_resolver.py:143:22-30: Attribute `stoploss` is implicitly defined by assignment in method `_normalize_attributes`, which is not a constructor [implicitly-defined-attribute]
- ERROR freqtrade/resolvers/strategy_resolver.py:145:22-37: Attribute `max_open_trades` is implicitly defined by assignment in method `_normalize_attributes`, which is not a constructor [implicitly-defined-attribute]
- ERROR freqtrade/resolvers/strategy_resolver.py:244:22-46: Attribute `_ft_stop_uses_after_fill` is implicitly defined by assignment in method `validate_strategy`, which is not a constructor [implicitly-defined-attribute]

pwndbg (https://github.com/pwndbg/pwndbg)
- ERROR pwndbg/commands/__init__.py:304:20-24: Attribute `prog` is implicitly defined by assignment in method `initialize_parser_recursively`, which is not a constructor [implicitly-defined-attribute]
- ERROR pwndbg/commands/__init__.py:378:16-31: Attribute `formatter_class` is implicitly defined by assignment in method `initialize_parser_recursively`, which is not a constructor [implicitly-defined-attribute]

manticore (https://github.com/trailofbits/manticore)
- ERROR manticore/native/cpu/cpufactory.py:34:13-16: Attribute `cpu` is implicitly defined by assignment in method `get_cpu`, which is not a constructor [implicitly-defined-attribute]

mitmproxy (https://github.com/mitmproxy/mitmproxy)
- ERROR docs/src/examples/contrib/ntlm_upstream_proxy.py:96:18-30: Attribute `ntlm_context` is implicitly defined by assignment in method `running`, which is not a constructor [implicitly-defined-attribute]
- ERROR docs/src/examples/contrib/ntlm_upstream_proxy.py:98:18-22: Attribute `flow` is implicitly defined by assignment in method `running`, which is not a constructor [implicitly-defined-attribute]
- ERROR examples/contrib/ntlm_upstream_proxy.py:96:18-30: Attribute `ntlm_context` is implicitly defined by assignment in method `running`, which is not a constructor [implicitly-defined-attribute]
- ERROR examples/contrib/ntlm_upstream_proxy.py:98:18-22: Attribute `flow` is implicitly defined by assignment in method `running`, which is not a constructor [implicitly-defined-attribute]

cloud-init (https://github.com/canonical/cloud-init)
- ERROR tests/unittests/sources/test_lxd.py:194:18-35: Attribute `_crawled_metadata` is implicitly defined by assignment in method `test_provided_network_config`, which is not a constructor [implicitly-defined-attribute]

strawberry (https://github.com/strawberry-graphql/strawberry)
- ERROR strawberry/schema/base.py:120:19-26: Protocol variables must be explicitly declared in the class body [protocol-implicitly-defined-attribute]

anyio (https://github.com/agronholm/anyio)
- ERROR src/anyio/_backends/_trio.py:740:17-21: Attribute `args` is implicitly defined by assignment in method `_convert_runtime_error_msg`, which is not a constructor [implicitly-defined-attribute]
- ERROR src/anyio/_backends/_trio.py:740:17-21: Object of class `Lock` has no attribute `args` (not declared in `__slots__`) [missing-attribute]

hydpy (https://github.com/hydpy-dev/hydpy)
- ERROR hydpy/models/lland/lland_model.py:3705:23-30: Attribute `idx_hru` is implicitly defined by assignment in method `__call__`, which is not a constructor [implicitly-defined-attribute]
- ERROR hydpy/models/lland/lland_model.py:4255:23-30: Attribute `idx_hru` is implicitly defined by assignment in method `__call__`, which is not a constructor [implicitly-defined-attribute]
- ERROR hydpy/models/lland/lland_model.py:4439:23-30: Attribute `idx_hru` is implicitly defined by assignment in method `__call__`, which is not a constructor [implicitly-defined-attribute]
- ERROR hydpy/models/sw1d/sw1d_model.py:689:19-27: Attribute `timeleft` is implicitly defined by assignment in method `__call__`, which is not a constructor [implicitly-defined-attribute]

meson (https://github.com/mesonbuild/meson)
- ERROR mesonbuild/msubprojects.py:146:17-25: Attribute `releases` is implicitly defined by assignment in method `pre_update_wrapdb`, which is not a constructor [implicitly-defined-attribute]

dd-trace-py (https://github.com/DataDog/dd-trace-py)
- ERROR ddtrace/llmobs/_integrations/openai.py:179:14-18: Attribute `name` is implicitly defined by assignment in method `_llmobs_set_tags_from_tool`, which is not a constructor [implicitly-defined-attribute]

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.

Redefinition of instance variable.

2 participants