Skip to content

Commit 8adb648

Browse files
grievejiafacebook-github-bot
authored andcommitted
Add a flag to ClassFieldInitialization::Instance indicating whether the instance field must have been intialized or not
Summary: Currently, if a field declared on class toplevel is not initialized immediately on the class toplevel, we always assume that it must never have been initialized. E.g. ``` class Foo: x: int Foo.x # ERROR! This is banned because `x` must have never been initialized ``` But there are several cases where this assumption is too wide-sweeping. For example, when `x` is annotated as `ClassVar[int]`, or when `Foo` is defined in stub files (see D74035159), it's actually more desirable if we assume `x` is "magically initialized" somehow and avoid reporting errors on `Foo.x`. This diff proposes we attach a small piece of data to `ClassFieldInitialization::Instance` indicating whether we should consider `x` to be "magically initialized", to make it possible to suppress relevant errors by default. Only the data is added in this diff -- no logic is reading from the data yet. We'll be adding downstream readers of the data in D74035159 Reviewed By: rchen152 Differential Revision: D74035160 fbshipit-source-id: e58a2f60208ccd7b7d5ca2e6d1b142f43c0a420f
1 parent 762fbe9 commit 8adb648

File tree

2 files changed

+12
-10
lines changed

2 files changed

+12
-10
lines changed

pyrefly/lib/alt/class/class_field.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,16 @@ pub enum ClassFieldInitialization {
6969
/// If this is a dataclass field, BoolKeywords stores the field's dataclass
7070
/// flags (which are boolean options that control how fields behave).
7171
Class(Option<BoolKeywords>),
72-
Instance,
72+
/// The boolean indicates whether we know the field may have been initialized
73+
/// outside of the class body or not.
74+
Instance(bool),
7375
}
7476

7577
impl Display for ClassFieldInitialization {
7678
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7779
match self {
7880
Self::Class(_) => write!(f, "initialized in body"),
79-
Self::Instance => write!(f, "not initialized in body"),
81+
Self::Instance(_) => write!(f, "not initialized in body"),
8082
}
8183
}
8284
}
@@ -232,7 +234,7 @@ impl ClassField {
232234
match self.instantiate_for(instance).0 {
233235
ClassFieldInner::Simple { ty, .. } => match self.initialization() {
234236
ClassFieldInitialization::Class(_) => Some(ty),
235-
ClassFieldInitialization::Instance => None,
237+
ClassFieldInitialization::Instance(_) => None,
236238
},
237239
}
238240
}
@@ -255,7 +257,7 @@ impl ClassField {
255257
..
256258
} => Required::Optional,
257259
ClassFieldInner::Simple {
258-
initialization: ClassFieldInitialization::Instance,
260+
initialization: ClassFieldInitialization::Instance(_),
259261
..
260262
} => Required::Required,
261263
}
@@ -346,7 +348,7 @@ impl ClassField {
346348
kws.set(DataclassKeywords::DEFAULT.0, true);
347349
kws
348350
}
349-
ClassFieldInitialization::Instance => BoolKeywords::new(),
351+
ClassFieldInitialization::Instance(_) => BoolKeywords::new(),
350352
};
351353
if kw_only {
352354
flags.set(DataclassKeywords::KW_ONLY.0, true);
@@ -743,7 +745,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
743745
initial_value: &ClassFieldInitialValue,
744746
) -> ClassFieldInitialization {
745747
match initial_value {
746-
ClassFieldInitialValue::Instance(_) => ClassFieldInitialization::Instance,
748+
ClassFieldInitialValue::Instance(_) => ClassFieldInitialization::Instance(false),
747749
ClassFieldInitialValue::Class(None) => ClassFieldInitialization::Class(None),
748750
ClassFieldInitialValue::Class(Some(e)) => {
749751
// If this field was created via a call to a dataclass field specifier, extract field flags from the call.
@@ -892,10 +894,10 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
892894
ClassFieldInitialization::Class(_) => {
893895
bind_instance_attribute(instance, ty, is_class_var, readonly)
894896
}
895-
ClassFieldInitialization::Instance if readonly || is_class_var => {
897+
ClassFieldInitialization::Instance(_) if readonly || is_class_var => {
896898
Attribute::read_only(ty)
897899
}
898-
ClassFieldInitialization::Instance => Attribute::read_write(ty),
900+
ClassFieldInitialization::Instance(_) => Attribute::read_write(ty),
899901
}
900902
}
901903
}
@@ -917,7 +919,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
917919
)
918920
}
919921
ClassFieldInner::Simple {
920-
initialization: ClassFieldInitialization::Instance,
922+
initialization: ClassFieldInitialization::Instance(_),
921923
annotation,
922924
..
923925
} if annotation

pyrefly/lib/alt/class/enums.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
4343
return false;
4444
}
4545
// Enum members must be initialized on the class
46-
if *initialization == ClassFieldInitialization::Instance {
46+
if matches!(*initialization, ClassFieldInitialization::Instance(_)) {
4747
return false;
4848
}
4949
match ty {

0 commit comments

Comments
 (0)