Skip to content

fix: ClassVar[Final[...]] collapses to Any instead of inner type (#21906) - #22012

Open
chenzeyan54-commits wants to merge 1 commit into
python:masterfrom
chenzeyan54-commits:fix/classvar-final-inner-type-21906
Open

chenzeyan54-commits wants to merge 1 commit into
python:masterfrom
chenzeyan54-commits:fix/classvar-final-inner-type-21906

Conversation

@chenzeyan54-commits

Copy link
Copy Markdown

Summary

Fixes #21906

On Python 3.13+, ClassVar[Final[...]] accepts the annotation (no valid-type
error), but the variable's type still silently collapses to
AnyType(from_error), losing all type information.

Root Cause

In try_analyze_special_unbound_type's FINAL_TYPE_NAMES branch, when
self.allow_final is True (i.e. the nested Final is legitimately
accepted, e.g. inside ClassVar[Final[...]] on 3.13+), the code fell
through to return AnyType(TypeOfAny.from_error) instead of analyzing the
inner type.

Fix

In the same branch, when self.allow_final is True and the Final has
type arguments, preserve and return the inner type by recursing into
anal_type(t.args[0]):

elif not self.allow_final:
    self.fail(
        "Final can be only used as an outermost qualifier ...",
        t, code=codes.VALID_TYPE,
    )
elif t.args:
    # Nested Final[...] is accepted here (e.g. ClassVar[Final[...]] on 3.13+);
    # preserve and return the inner type instead of collapsing to Any.
    return self.anal_type(t.args[0])
return AnyType(TypeOfAny.from_error)

Verification

  • Added regression guard testFinalUsedWithClassVarAfterPy313PreservesType in
    test-data/unit/check-final.testreveal_type(A.cv) reports
    builtins.dict[type[B], __main__.A instead of Any.
  • Existing testFinalUsedWithClassVarAfterPy313 (no error) and
    testFinalUsedWithClassVar (3.12 still errors) are unaffected.

…hon#21906)

Nested Final inside ClassVar on Python 3.13+ accepts the annotation
(no valid-type error) but the variable's type still collapsed to
AnyType(from_error), silently losing type information.

In try_analyze_special_unbound_type's FINAL_TYPE_NAMES branch, when
self.allow_final is True (i.e. the nested Final is legitimately accepted
in this context), preserve and return the inner type instead of falling
through to AnyType(from_error).

Regression guard: testFinalUsedWithClassVarAfterPy313PreservesType.
@github-actions

Copy link
Copy Markdown
Contributor

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mypy treating type of final class variable in dataclass as Any

1 participant