@@ -18,11 +18,12 @@ use crate::semantic_index::ast_ids::node_key::ExpressionNodeKey;
18
18
use crate :: semantic_index:: ast_ids:: AstIdsBuilder ;
19
19
use crate :: semantic_index:: definition:: {
20
20
AnnotatedAssignmentDefinitionKind , AnnotatedAssignmentDefinitionNodeRef ,
21
- AssignmentDefinitionKind , AssignmentDefinitionNodeRef , ComprehensionDefinitionNodeRef ,
22
- Definition , DefinitionCategory , DefinitionKind , DefinitionNodeKey , DefinitionNodeRef ,
23
- Definitions , ExceptHandlerDefinitionNodeRef , ForStmtDefinitionKind , ForStmtDefinitionNodeRef ,
24
- ImportDefinitionNodeRef , ImportFromDefinitionNodeRef , MatchPatternDefinitionNodeRef ,
25
- StarImportDefinitionNodeRef , TargetKind , WithItemDefinitionKind , WithItemDefinitionNodeRef ,
21
+ AssignmentDefinitionKind , AssignmentDefinitionNodeRef , ComprehensionDefinitionKind ,
22
+ ComprehensionDefinitionNodeRef , Definition , DefinitionCategory , DefinitionKind ,
23
+ DefinitionNodeKey , DefinitionNodeRef , Definitions , ExceptHandlerDefinitionNodeRef ,
24
+ ForStmtDefinitionKind , ForStmtDefinitionNodeRef , ImportDefinitionNodeRef ,
25
+ ImportFromDefinitionNodeRef , MatchPatternDefinitionNodeRef , StarImportDefinitionNodeRef ,
26
+ TargetKind , WithItemDefinitionKind , WithItemDefinitionNodeRef ,
26
27
} ;
27
28
use crate :: semantic_index:: expression:: { Expression , ExpressionKind } ;
28
29
use crate :: semantic_index:: predicate:: {
@@ -850,31 +851,35 @@ impl<'db> SemanticIndexBuilder<'db> {
850
851
851
852
// The `iter` of the first generator is evaluated in the outer scope, while all subsequent
852
853
// nodes are evaluated in the inner scope.
853
- self . add_standalone_expression ( & generator. iter ) ;
854
+ let value = self . add_standalone_expression ( & generator. iter ) ;
854
855
self . visit_expr ( & generator. iter ) ;
855
856
self . push_scope ( scope) ;
856
857
857
- self . push_assignment ( CurrentAssignment :: Comprehension {
858
- node : generator,
859
- first : true ,
860
- } ) ;
861
- self . visit_expr ( & generator. target ) ;
862
- self . pop_assignment ( ) ;
858
+ self . add_unpackable_assignment (
859
+ & Unpackable :: Comprehension {
860
+ node : generator,
861
+ first : true ,
862
+ } ,
863
+ & generator. target ,
864
+ value,
865
+ ) ;
863
866
864
867
for expr in & generator. ifs {
865
868
self . visit_expr ( expr) ;
866
869
}
867
870
868
871
for generator in generators_iter {
869
- self . add_standalone_expression ( & generator. iter ) ;
872
+ let value = self . add_standalone_expression ( & generator. iter ) ;
870
873
self . visit_expr ( & generator. iter ) ;
871
874
872
- self . push_assignment ( CurrentAssignment :: Comprehension {
873
- node : generator,
874
- first : false ,
875
- } ) ;
876
- self . visit_expr ( & generator. target ) ;
877
- self . pop_assignment ( ) ;
875
+ self . add_unpackable_assignment (
876
+ & Unpackable :: Comprehension {
877
+ node : generator,
878
+ first : false ,
879
+ } ,
880
+ & generator. target ,
881
+ value,
882
+ ) ;
878
883
879
884
for expr in & generator. ifs {
880
885
self . visit_expr ( expr) ;
@@ -933,9 +938,30 @@ impl<'db> SemanticIndexBuilder<'db> {
933
938
934
939
let current_assignment = match target {
935
940
ast:: Expr :: List ( _) | ast:: Expr :: Tuple ( _) => {
941
+ if matches ! ( unpackable, Unpackable :: Comprehension { .. } ) {
942
+ debug_assert_eq ! (
943
+ self . scopes[ self . current_scope( ) ] . node( ) . scope_kind( ) ,
944
+ ScopeKind :: Comprehension
945
+ ) ;
946
+ }
947
+ // The first iterator of the comprehension is evaluated in the outer scope, while all subsequent
948
+ // nodes are evaluated in the inner scope.
949
+ // SAFETY: The current scope is the comprehension, and the comprehension scope must have a parent scope.
950
+ let value_file_scope =
951
+ if let Unpackable :: Comprehension { first : true , .. } = unpackable {
952
+ self . scope_stack
953
+ . iter ( )
954
+ . rev ( )
955
+ . nth ( 1 )
956
+ . expect ( "The comprehension scope must have a parent scope" )
957
+ . file_scope_id
958
+ } else {
959
+ self . current_scope ( )
960
+ } ;
936
961
let unpack = Some ( Unpack :: new (
937
962
self . db ,
938
963
self . file ,
964
+ value_file_scope,
939
965
self . current_scope ( ) ,
940
966
// SAFETY: `target` belongs to the `self.module` tree
941
967
#[ allow( unsafe_code) ]
@@ -1804,7 +1830,7 @@ where
1804
1830
let node_key = NodeKey :: from_node ( expr) ;
1805
1831
1806
1832
match expr {
1807
- ast:: Expr :: Name ( name_node @ ast:: ExprName { id, ctx, .. } ) => {
1833
+ ast:: Expr :: Name ( ast:: ExprName { id, ctx, .. } ) => {
1808
1834
let ( is_use, is_definition) = match ( ctx, self . current_assignment ( ) ) {
1809
1835
( ast:: ExprContext :: Store , Some ( CurrentAssignment :: AugAssign ( _) ) ) => {
1810
1836
// For augmented assignment, the target expression is also used.
@@ -1867,12 +1893,17 @@ where
1867
1893
// implemented.
1868
1894
self . add_definition ( symbol, named) ;
1869
1895
}
1870
- Some ( CurrentAssignment :: Comprehension { node, first } ) => {
1896
+ Some ( CurrentAssignment :: Comprehension {
1897
+ unpack,
1898
+ node,
1899
+ first,
1900
+ } ) => {
1871
1901
self . add_definition (
1872
1902
symbol,
1873
1903
ComprehensionDefinitionNodeRef {
1904
+ unpack,
1874
1905
iterable : & node. iter ,
1875
- target : name_node ,
1906
+ target : expr ,
1876
1907
first,
1877
1908
is_async : node. is_async ,
1878
1909
} ,
@@ -2143,14 +2174,37 @@ where
2143
2174
DefinitionKind :: WithItem ( assignment) ,
2144
2175
) ;
2145
2176
}
2146
- Some ( CurrentAssignment :: Comprehension { .. } ) => {
2147
- // TODO:
2177
+ Some ( CurrentAssignment :: Comprehension {
2178
+ unpack,
2179
+ node,
2180
+ first,
2181
+ } ) => {
2182
+ // SAFETY: `iter` and `expr` belong to the `self.module` tree
2183
+ #[ allow( unsafe_code) ]
2184
+ let assignment = ComprehensionDefinitionKind {
2185
+ target_kind : TargetKind :: from ( unpack) ,
2186
+ iterable : unsafe {
2187
+ AstNodeRef :: new ( self . module . clone ( ) , & node. iter )
2188
+ } ,
2189
+ target : unsafe { AstNodeRef :: new ( self . module . clone ( ) , expr) } ,
2190
+ first,
2191
+ is_async : node. is_async ,
2192
+ } ;
2193
+ // Temporarily move to the scope of the method to which the instance attribute is defined.
2194
+ // SAFETY: `self.scope_stack` is not empty because the targets in comprehensions should always introduce a new scope.
2195
+ let scope = self . scope_stack . pop ( ) . expect ( "The popped scope must be a comprehension, which must have a parent scope" ) ;
2196
+ self . register_attribute_assignment (
2197
+ object,
2198
+ attr,
2199
+ DefinitionKind :: Comprehension ( assignment) ,
2200
+ ) ;
2201
+ self . scope_stack . push ( scope) ;
2148
2202
}
2149
2203
Some ( CurrentAssignment :: AugAssign ( _) ) => {
2150
2204
// TODO:
2151
2205
}
2152
2206
Some ( CurrentAssignment :: Named ( _) ) => {
2153
- // TODO:
2207
+ // A named expression whose target is an attribute is syntactically prohibited
2154
2208
}
2155
2209
None => { }
2156
2210
}
@@ -2244,6 +2298,7 @@ enum CurrentAssignment<'a> {
2244
2298
Comprehension {
2245
2299
node : & ' a ast:: Comprehension ,
2246
2300
first : bool ,
2301
+ unpack : Option < ( UnpackPosition , Unpack < ' a > ) > ,
2247
2302
} ,
2248
2303
WithItem {
2249
2304
item : & ' a ast:: WithItem ,
@@ -2257,11 +2312,9 @@ impl CurrentAssignment<'_> {
2257
2312
match self {
2258
2313
Self :: Assign { unpack, .. }
2259
2314
| Self :: For { unpack, .. }
2260
- | Self :: WithItem { unpack, .. } => unpack. as_mut ( ) . map ( |( position, _) | position) ,
2261
- Self :: AnnAssign ( _)
2262
- | Self :: AugAssign ( _)
2263
- | Self :: Named ( _)
2264
- | Self :: Comprehension { .. } => None ,
2315
+ | Self :: WithItem { unpack, .. }
2316
+ | Self :: Comprehension { unpack, .. } => unpack. as_mut ( ) . map ( |( position, _) | position) ,
2317
+ Self :: AnnAssign ( _) | Self :: AugAssign ( _) | Self :: Named ( _) => None ,
2265
2318
}
2266
2319
}
2267
2320
}
@@ -2316,13 +2369,17 @@ enum Unpackable<'a> {
2316
2369
item : & ' a ast:: WithItem ,
2317
2370
is_async : bool ,
2318
2371
} ,
2372
+ Comprehension {
2373
+ first : bool ,
2374
+ node : & ' a ast:: Comprehension ,
2375
+ } ,
2319
2376
}
2320
2377
2321
2378
impl < ' a > Unpackable < ' a > {
2322
2379
const fn kind ( & self ) -> UnpackKind {
2323
2380
match self {
2324
2381
Unpackable :: Assign ( _) => UnpackKind :: Assign ,
2325
- Unpackable :: For ( _) => UnpackKind :: Iterable ,
2382
+ Unpackable :: For ( _) | Unpackable :: Comprehension { .. } => UnpackKind :: Iterable ,
2326
2383
Unpackable :: WithItem { .. } => UnpackKind :: ContextManager ,
2327
2384
}
2328
2385
}
@@ -2337,6 +2394,11 @@ impl<'a> Unpackable<'a> {
2337
2394
is_async : * is_async,
2338
2395
unpack,
2339
2396
} ,
2397
+ Unpackable :: Comprehension { node, first } => CurrentAssignment :: Comprehension {
2398
+ node,
2399
+ first : * first,
2400
+ unpack,
2401
+ } ,
2340
2402
}
2341
2403
}
2342
2404
}
0 commit comments