Skip to content

Commit 2b96bdb

Browse files
rchen152facebook-github-bot
authored andcommitted
Improve organization of and add comments to class_metadata_of.
Summary: This is my last change (for now) to `class_metadata_of` - now that it's smaller and easier to understand, organize it into commented sections. Reviewed By: grievejia Differential Revision: D80373735 fbshipit-source-id: 911753c99e40a8ab4203fff4bcb998cd5c5977b5
1 parent 9f68e47 commit 2b96bdb

File tree

1 file changed

+59
-41
lines changed

1 file changed

+59
-41
lines changed

pyrefly/lib/alt/class/class_metadata.rs

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,13 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
102102
pydantic_metadata_binding: &PydanticMetadataBinding,
103103
errors: &ErrorCollector,
104104
) -> ClassMetadata {
105+
// Get class decorators.
105106
let decorators = decorators.map(|(decorator_key, decorator_range)| {
106107
(self.get_idx(*decorator_key), *decorator_range)
107108
});
109+
110+
// Get full base class list and compute data that depends on the `BaseClass` representation
111+
// of base classes.
108112
let bases = if let Some(special_base) = special_base {
109113
bases
110114
.iter()
@@ -118,6 +122,8 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
118122
let has_generic_base_class = bases.iter().any(|x| x.is_generic());
119123
let has_typed_dict_base_class = bases.iter().any(|x| x.is_typed_dict());
120124

125+
// Parse base classes and compute data that depends on the `BaseClassParseResult`
126+
// representation of base classes.
121127
let parsed_results = bases
122128
.into_iter()
123129
.map(|x| self.parse_base_class(x, is_new_type))
@@ -129,44 +135,16 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
129135
&parsed_results,
130136
errors,
131137
);
138+
139+
// Compute base classes with metadata.
132140
let bases_with_metadata = self.bases_with_metadata(parsed_results, is_new_type, errors);
133-
let has_base_any = contains_base_class_any
134-
|| bases_with_metadata
135-
.iter()
136-
.any(|(_, metadata)| metadata.has_base_any());
137141

138-
let named_tuple_metadata = self.named_tuple_metadata(cls, &bases_with_metadata, errors);
139-
if named_tuple_metadata.is_some() && bases_with_metadata.len() > 1 {
140-
self.error(
141-
errors,
142-
cls.range(),
143-
ErrorInfo::Kind(ErrorKind::InvalidInheritance),
144-
"Named tuples do not support multiple inheritance".to_owned(),
145-
);
146-
}
142+
// Compute class keywords, including the metaclass.
147143
let (metaclasses, keywords): (Vec<_>, Vec<(_, _)>) =
148144
keywords.iter().partition_map(|(n, x)| match n.as_str() {
149145
"metaclass" => Either::Left(x),
150146
_ => Either::Right((n.clone(), self.expr_infer(x, errors))),
151147
});
152-
let pydantic_metadata =
153-
self.pydantic_metadata(&bases_with_metadata, pydantic_metadata_binding);
154-
155-
let is_typed_dict = has_typed_dict_base_class
156-
|| bases_with_metadata
157-
.iter()
158-
.any(|(_, metadata)| metadata.is_typed_dict());
159-
if is_typed_dict
160-
&& let Some(bad) = bases_with_metadata.iter().find(|x| !x.1.is_typed_dict())
161-
{
162-
self.error(errors,
163-
cls.range(),
164-
ErrorInfo::Kind(ErrorKind::InvalidInheritance),
165-
format!("`{}` is not a typed dictionary. Typed dictionary definitions may only extend other typed dictionaries.", bad.0.name()),
166-
);
167-
}
168-
let typed_dict_metadata =
169-
self.typed_dict_metadata(cls, &bases_with_metadata, &keywords, is_typed_dict, errors);
170148
let base_metaclasses = bases_with_metadata
171149
.iter()
172150
.filter_map(|(b, metadata)| metadata.metaclass().map(|m| (b.name(), m)))
@@ -177,18 +155,8 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
177155
&base_metaclasses,
178156
errors,
179157
);
180-
let enum_metadata =
181-
self.enum_metadata(cls, metaclass.as_ref(), &bases_with_metadata, errors);
182158
if let Some(metaclass) = &metaclass {
183159
self.check_base_class_metaclasses(cls, metaclass, &base_metaclasses, errors);
184-
if is_typed_dict {
185-
self.error(
186-
errors,
187-
cls.range(),
188-
ErrorInfo::Kind(ErrorKind::InvalidInheritance),
189-
"Typed dictionary definitions may not specify a metaclass".to_owned(),
190-
);
191-
}
192160
if metaclass.targs().as_slice().iter().any(|targ| {
193161
targ.any(|ty| {
194162
matches!(
@@ -205,9 +173,57 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
205173
);
206174
}
207175
}
176+
177+
// Compute various pieces of special metadata.
178+
let has_base_any = contains_base_class_any
179+
|| bases_with_metadata
180+
.iter()
181+
.any(|(_, metadata)| metadata.has_base_any());
182+
183+
let named_tuple_metadata = self.named_tuple_metadata(cls, &bases_with_metadata, errors);
184+
if named_tuple_metadata.is_some() && bases_with_metadata.len() > 1 {
185+
self.error(
186+
errors,
187+
cls.range(),
188+
ErrorInfo::Kind(ErrorKind::InvalidInheritance),
189+
"Named tuples do not support multiple inheritance".to_owned(),
190+
);
191+
}
192+
193+
let pydantic_metadata =
194+
self.pydantic_metadata(&bases_with_metadata, pydantic_metadata_binding);
195+
196+
let is_typed_dict = has_typed_dict_base_class
197+
|| bases_with_metadata
198+
.iter()
199+
.any(|(_, metadata)| metadata.is_typed_dict());
200+
if is_typed_dict
201+
&& let Some(bad) = bases_with_metadata.iter().find(|x| !x.1.is_typed_dict())
202+
{
203+
self.error(errors,
204+
cls.range(),
205+
ErrorInfo::Kind(ErrorKind::InvalidInheritance),
206+
format!("`{}` is not a typed dictionary. Typed dictionary definitions may only extend other typed dictionaries.", bad.0.name()),
207+
);
208+
}
209+
let typed_dict_metadata =
210+
self.typed_dict_metadata(cls, &bases_with_metadata, &keywords, is_typed_dict, errors);
211+
if metaclass.is_some() && is_typed_dict {
212+
self.error(
213+
errors,
214+
cls.range(),
215+
ErrorInfo::Kind(ErrorKind::InvalidInheritance),
216+
"Typed dictionary definitions may not specify a metaclass".to_owned(),
217+
);
218+
}
219+
220+
let enum_metadata =
221+
self.enum_metadata(cls, metaclass.as_ref(), &bases_with_metadata, errors);
222+
208223
let is_final = decorators.iter().any(|(decorator, _)| {
209224
decorator.ty().callee_kind() == Some(CalleeKind::Function(FunctionKind::Final))
210225
});
226+
211227
let total_ordering_metadata = decorators.iter().find_map(|(decorator, decorator_range)| {
212228
decorator.ty().callee_kind().and_then(|kind| {
213229
if kind == CalleeKind::Function(FunctionKind::TotalOrdering) {
@@ -219,6 +235,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
219235
}
220236
})
221237
});
238+
222239
// If this class inherits from a dataclass_transform-ed class, record the defaults that we
223240
// should use for dataclass parameters.
224241
let dataclass_defaults_from_base_class = bases_with_metadata
@@ -245,6 +262,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
245262
self.validate_frozen_dataclass_inheritance(cls, dm, &bases_with_metadata, errors);
246263
}
247264

265+
// Compute final base class list.
248266
let bases = if is_typed_dict && bases_with_metadata.is_empty() {
249267
// This is a "fallback" class that contains attributes that are available on all TypedDict subclasses.
250268
// Note that this also makes those attributes available on *instances* of said subclasses; this is

0 commit comments

Comments
 (0)