@@ -98,6 +98,8 @@ impl Ranged for AttributeAssignment<'_> {
98
98
}
99
99
100
100
/// Return a list of attributes that are assigned to but not included in `__slots__`.
101
+ ///
102
+ /// If the `__slots__` attribute cannot be statically determined, returns an empty vector.
101
103
fn is_attributes_not_in_slots ( body : & [ Stmt ] ) -> Vec < AttributeAssignment > {
102
104
// First, collect all the attributes that are assigned to `__slots__`.
103
105
let mut slots = FxHashSet :: default ( ) ;
@@ -110,7 +112,13 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
110
112
} ;
111
113
112
114
if id == "__slots__" {
113
- slots. extend ( slots_attributes ( value) ) ;
115
+ for attribute in slots_attributes ( value) {
116
+ if let Some ( attribute) = attribute {
117
+ slots. insert ( attribute) ;
118
+ } else {
119
+ return vec ! [ ] ;
120
+ }
121
+ }
114
122
}
115
123
}
116
124
@@ -125,7 +133,13 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
125
133
} ;
126
134
127
135
if id == "__slots__" {
128
- slots. extend ( slots_attributes ( value) ) ;
136
+ for attribute in slots_attributes ( value) {
137
+ if let Some ( attribute) = attribute {
138
+ slots. insert ( attribute) ;
139
+ } else {
140
+ return vec ! [ ] ;
141
+ }
142
+ }
129
143
}
130
144
}
131
145
@@ -136,7 +150,13 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
136
150
} ;
137
151
138
152
if id == "__slots__" {
139
- slots. extend ( slots_attributes ( value) ) ;
153
+ for attribute in slots_attributes ( value) {
154
+ if let Some ( attribute) = attribute {
155
+ slots. insert ( attribute) ;
156
+ } else {
157
+ return vec ! [ ] ;
158
+ }
159
+ }
140
160
}
141
161
}
142
162
_ => { }
@@ -237,12 +257,14 @@ fn is_attributes_not_in_slots(body: &[Stmt]) -> Vec<AttributeAssignment> {
237
257
}
238
258
239
259
/// Return an iterator over the attributes enumerated in the given `__slots__` value.
240
- fn slots_attributes ( expr : & Expr ) -> impl Iterator < Item = & str > {
260
+ ///
261
+ /// If an attribute can't be statically determined, it will be `None`.
262
+ fn slots_attributes ( expr : & Expr ) -> impl Iterator < Item = Option < & str > > {
241
263
// Ex) `__slots__ = ("name",)`
242
264
let elts_iter = match expr {
243
265
Expr :: Tuple ( ast:: ExprTuple { elts, .. } )
244
266
| Expr :: List ( ast:: ExprList { elts, .. } )
245
- | Expr :: Set ( ast:: ExprSet { elts, .. } ) => Some ( elts. iter ( ) . filter_map ( |elt| match elt {
267
+ | Expr :: Set ( ast:: ExprSet { elts, .. } ) => Some ( elts. iter ( ) . map ( |elt| match elt {
246
268
Expr :: StringLiteral ( ast:: ExprStringLiteral { value, .. } ) => Some ( value. to_str ( ) ) ,
247
269
_ => None ,
248
270
} ) ) ,
@@ -251,7 +273,7 @@ fn slots_attributes(expr: &Expr) -> impl Iterator<Item = &str> {
251
273
252
274
// Ex) `__slots__ = {"name": ...}`
253
275
let keys_iter = match expr {
254
- Expr :: Dict ( dict) => Some ( dict. iter_keys ( ) . filter_map ( |key| match key {
276
+ Expr :: Dict ( dict) => Some ( dict. iter_keys ( ) . map ( |key| match key {
255
277
Some ( Expr :: StringLiteral ( ast:: ExprStringLiteral { value, .. } ) ) => Some ( value. to_str ( ) ) ,
256
278
_ => None ,
257
279
} ) ) ,
0 commit comments