Skip to content

Commit ce5d000

Browse files
rchen152meta-codesync[bot]
authored andcommitted
Allow a ClassVar to be overridden with a nested class def and vice versa
Summary: Fixes #2543. Reviewed By: yangdanny97 Differential Revision: D95405904 fbshipit-source-id: 24c3dd55eca1073e9c60b6368e1abebb40308d1e
1 parent ea9de94 commit ce5d000

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

pyrefly/lib/alt/class/class_field.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4167,9 +4167,19 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
41674167
(ClassAttribute::NoAccess(_), _) => return Err(Box::new(AttrSubsetError::NoAccess)),
41684168
_ => {}
41694169
}
4170-
let got_is_classvar = matches!(got, ClassAttribute::ReadOnly(_, ReadOnlyReason::ClassVar));
4171-
let want_is_classvar =
4172-
matches!(want, ClassAttribute::ReadOnly(_, ReadOnlyReason::ClassVar));
4170+
// Both ClassVar and ClassObjectInitializedOnBody represent class-level read-only
4171+
// attributes, so they are compatible for override purposes.
4172+
let is_classvar_compatible = |attr: &ClassAttribute| {
4173+
matches!(
4174+
attr,
4175+
ClassAttribute::ReadOnly(
4176+
_,
4177+
ReadOnlyReason::ClassVar | ReadOnlyReason::ClassObjectInitializedOnBody
4178+
)
4179+
)
4180+
};
4181+
let got_is_classvar = is_classvar_compatible(got);
4182+
let want_is_classvar = is_classvar_compatible(want);
41734183
if got_is_classvar != want_is_classvar {
41744184
return Err(Box::new(AttrSubsetError::ClassVarMismatch {
41754185
got_is_classvar,

pyrefly/lib/test/class_overrides.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,34 @@ class E(B):
7272
"#,
7373
);
7474

75+
testcase!(
76+
test_override_classvar_with_nested_class,
77+
r#"
78+
from typing import ClassVar
79+
80+
class Endpoint: ...
81+
82+
class Base:
83+
endpoint_cls: ClassVar[type[Endpoint]] = Endpoint
84+
85+
class Child(Base):
86+
class endpoint_cls(Endpoint): ...
87+
"#,
88+
);
89+
90+
testcase!(
91+
test_override_nested_class_with_classvar,
92+
r#"
93+
from typing import ClassVar
94+
95+
class Base:
96+
class endpoint_cls: ...
97+
98+
class Child(Base):
99+
endpoint_cls: ClassVar[type[Base.endpoint_cls]] = type("endpoint_cls", (Base.endpoint_cls,), {})
100+
"#,
101+
);
102+
75103
testcase!(
76104
test_override_final_var,
77105
r#"

0 commit comments

Comments
 (0)