Skip to content

fix: Allow attribute access on union types containing Any #557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

kimasplund
Copy link

Summary

This PR fixes false positive errors when accessing attributes on union types that contain Any.

Issue #549: False Positive "missing-attribute" on Union Types

When a union type contains Any (e.g., A < /dev/null | Any), Pyrefly was incorrectly reporting missing attribute errors for the non-Any members of the union. According to gradual typing principles, Any should allow any operation.

Changes

  1. Added type_contains_any() helper method that recursively checks if a type contains Any
  2. Modified attribute access, assignment, and deletion to:
    • Check if the base type contains Any
    • If yes, return Any without generating errors
    • If no, proceed with normal type checking

Tests

Added comprehensive tests in issue_549_any_union.rs:

  • ✅ Attribute access on A | Any unions (no errors)
  • ✅ Method calls on A | Any unions (no errors)
  • ✅ Attribute access on A | B unions without Any (still errors as expected)

Limitations

This fixes the issue for explicit unions like A | Any. The case of Dict[str, Any] subscript access expanding to unions needs separate handling and is not addressed in this PR.

Partially fixes #549

This commit adds test cases for four reported issues:

1. Issue facebook#547: Dict narrowing after None checks - Already fixed in current version
   - Tests confirm proper type narrowing for Optional[Dict] after is not None checks
   - Tests cover attribute chains, early returns, and nested narrowing

2. Issue facebook#548: Pydantic Field overload resolution
   - Tests document expected behavior with positional arguments
   - Issue stems from Pydantic's use of sentinel values in type stubs
   - Workaround: use keyword arguments (default=value)

3. Issue facebook#549: False positives on union types with Any
   - Added type_contains_any() helper to check for Any in unions
   - When Any is present in a union, allow any attribute access without errors
   - Partial fix: works for explicit unions, Dict[str, Any] needs separate handling

4. Issue facebook#550: Init helper methods
   - Tests document the limitation that helper methods aren't recognized
   - Full fix requires flow analysis to track methods called from __init__

These tests improve code coverage and document both working features
and known limitations, providing a foundation for future improvements.
When Any is present in a union type (e.g., A  < /dev/null |  Any), any attribute access
should be allowed without generating errors for the non-Any members.

This commit adds type_contains_any() helper that recursively checks if a
type contains Any, and modifies attribute access/assignment/deletion to
return Any without errors when true.

Fixes facebook#549 (partially - explicit unions work, Dict[str, Any] needs separate handling)
@erictraut
Copy link

The change implemented in this PR looks incorrect to me from the standpoint of type theory and the Python typing spec.

I think the PR is based on an incorrect or incomplete understanding of unions and gradual types. For more details about how these work in the Python type system, refer to this section of the typing spec.

When accessing an attribute or a method on a union, that method or attribute must be accessible on all subtypes within the union. If one of those subtypes is Any, a type checker still needs to verify that the attribute or method is accessible on the other type in the union. This PR appears to disable all such checks if the union contains an Any. This will result in false negatives.

You can see that pyrefly's current behavior matches that of other type checkers including pyright and mypy.

@yangdanny97
Copy link
Contributor

For the reasons @erictraut mentioned, I don't think we can merge this PR. I'm going to close this, since TypedDicts appear to work as expected and we can track the plan to handle regular dictionaries in #324

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.

False Positive "missing-attribute" on Union Types
4 participants