@@ -102,9 +102,13 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
102
102
pydantic_metadata_binding : & PydanticMetadataBinding ,
103
103
errors : & ErrorCollector ,
104
104
) -> ClassMetadata {
105
+ // Get class decorators.
105
106
let decorators = decorators. map ( |( decorator_key, decorator_range) | {
106
107
( self . get_idx ( * decorator_key) , * decorator_range)
107
108
} ) ;
109
+
110
+ // Get full base class list and compute data that depends on the `BaseClass` representation
111
+ // of base classes.
108
112
let bases = if let Some ( special_base) = special_base {
109
113
bases
110
114
. iter ( )
@@ -118,6 +122,8 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
118
122
let has_generic_base_class = bases. iter ( ) . any ( |x| x. is_generic ( ) ) ;
119
123
let has_typed_dict_base_class = bases. iter ( ) . any ( |x| x. is_typed_dict ( ) ) ;
120
124
125
+ // Parse base classes and compute data that depends on the `BaseClassParseResult`
126
+ // representation of base classes.
121
127
let parsed_results = bases
122
128
. into_iter ( )
123
129
. map ( |x| self . parse_base_class ( x, is_new_type) )
@@ -129,44 +135,16 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
129
135
& parsed_results,
130
136
errors,
131
137
) ;
138
+
139
+ // Compute base classes with metadata.
132
140
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 ( ) ) ;
137
141
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.
147
143
let ( metaclasses, keywords) : ( Vec < _ > , Vec < ( _ , _ ) > ) =
148
144
keywords. iter ( ) . partition_map ( |( n, x) | match n. as_str ( ) {
149
145
"metaclass" => Either :: Left ( x) ,
150
146
_ => Either :: Right ( ( n. clone ( ) , self . expr_infer ( x, errors) ) ) ,
151
147
} ) ;
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) ;
170
148
let base_metaclasses = bases_with_metadata
171
149
. iter ( )
172
150
. filter_map ( |( b, metadata) | metadata. metaclass ( ) . map ( |m| ( b. name ( ) , m) ) )
@@ -177,18 +155,8 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
177
155
& base_metaclasses,
178
156
errors,
179
157
) ;
180
- let enum_metadata =
181
- self . enum_metadata ( cls, metaclass. as_ref ( ) , & bases_with_metadata, errors) ;
182
158
if let Some ( metaclass) = & metaclass {
183
159
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
- }
192
160
if metaclass. targs ( ) . as_slice ( ) . iter ( ) . any ( |targ| {
193
161
targ. any ( |ty| {
194
162
matches ! (
@@ -205,9 +173,57 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
205
173
) ;
206
174
}
207
175
}
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
+
208
223
let is_final = decorators. iter ( ) . any ( |( decorator, _) | {
209
224
decorator. ty ( ) . callee_kind ( ) == Some ( CalleeKind :: Function ( FunctionKind :: Final ) )
210
225
} ) ;
226
+
211
227
let total_ordering_metadata = decorators. iter ( ) . find_map ( |( decorator, decorator_range) | {
212
228
decorator. ty ( ) . callee_kind ( ) . and_then ( |kind| {
213
229
if kind == CalleeKind :: Function ( FunctionKind :: TotalOrdering ) {
@@ -219,6 +235,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
219
235
}
220
236
} )
221
237
} ) ;
238
+
222
239
// If this class inherits from a dataclass_transform-ed class, record the defaults that we
223
240
// should use for dataclass parameters.
224
241
let dataclass_defaults_from_base_class = bases_with_metadata
@@ -245,6 +262,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
245
262
self . validate_frozen_dataclass_inheritance ( cls, dm, & bases_with_metadata, errors) ;
246
263
}
247
264
265
+ // Compute final base class list.
248
266
let bases = if is_typed_dict && bases_with_metadata. is_empty ( ) {
249
267
// This is a "fallback" class that contains attributes that are available on all TypedDict subclasses.
250
268
// Note that this also makes those attributes available on *instances* of said subclasses; this is
0 commit comments