@@ -331,12 +331,15 @@ impl<'db> SemanticIndexBuilder<'db> {
331
331
self . current_use_def_map_mut ( ) . merge ( state) ;
332
332
}
333
333
334
- fn add_symbol ( & mut self , name : Name ) -> ScopedSymbolId {
334
+ /// Return a 2-element tuple, where the first element is the [`ScopedSymbolId`] of the
335
+ /// symbol added, and the second element is a boolean indicating whether the symbol was *newly*
336
+ /// added or not
337
+ fn add_symbol ( & mut self , name : Name ) -> ( ScopedSymbolId , bool ) {
335
338
let ( symbol_id, added) = self . current_symbol_table ( ) . add_symbol ( name) ;
336
339
if added {
337
340
self . current_use_def_map_mut ( ) . add_symbol ( symbol_id) ;
338
341
}
339
- symbol_id
342
+ ( symbol_id, added )
340
343
}
341
344
342
345
fn mark_symbol_bound ( & mut self , id : ScopedSymbolId ) {
@@ -516,6 +519,7 @@ impl<'db> SemanticIndexBuilder<'db> {
516
519
}
517
520
518
521
/// Records a visibility constraint by applying it to all live bindings and declarations.
522
+ #[ must_use = "A visibility constraint must always be negated after it is added" ]
519
523
fn record_visibility_constraint (
520
524
& mut self ,
521
525
predicate : Predicate < ' db > ,
@@ -747,7 +751,7 @@ impl<'db> SemanticIndexBuilder<'db> {
747
751
..
748
752
} ) => ( name, & None , default) ,
749
753
} ;
750
- let symbol = self . add_symbol ( name. id . clone ( ) ) ;
754
+ let ( symbol, _ ) = self . add_symbol ( name. id . clone ( ) ) ;
751
755
// TODO create Definition for PEP 695 typevars
752
756
// note that the "bound" on the typevar is a totally different thing than whether
753
757
// or not a name is "bound" by a typevar declaration; the latter is always true.
@@ -841,20 +845,20 @@ impl<'db> SemanticIndexBuilder<'db> {
841
845
self . declare_parameter ( parameter) ;
842
846
}
843
847
if let Some ( vararg) = parameters. vararg . as_ref ( ) {
844
- let symbol = self . add_symbol ( vararg. name . id ( ) . clone ( ) ) ;
848
+ let ( symbol, _ ) = self . add_symbol ( vararg. name . id ( ) . clone ( ) ) ;
845
849
self . add_definition (
846
850
symbol,
847
851
DefinitionNodeRef :: VariadicPositionalParameter ( vararg) ,
848
852
) ;
849
853
}
850
854
if let Some ( kwarg) = parameters. kwarg . as_ref ( ) {
851
- let symbol = self . add_symbol ( kwarg. name . id ( ) . clone ( ) ) ;
855
+ let ( symbol, _ ) = self . add_symbol ( kwarg. name . id ( ) . clone ( ) ) ;
852
856
self . add_definition ( symbol, DefinitionNodeRef :: VariadicKeywordParameter ( kwarg) ) ;
853
857
}
854
858
}
855
859
856
860
fn declare_parameter ( & mut self , parameter : & ' db ast:: ParameterWithDefault ) {
857
- let symbol = self . add_symbol ( parameter. name ( ) . id ( ) . clone ( ) ) ;
861
+ let ( symbol, _ ) = self . add_symbol ( parameter. name ( ) . id ( ) . clone ( ) ) ;
858
862
859
863
let definition = self . add_definition ( symbol, parameter) ;
860
864
@@ -1071,7 +1075,7 @@ where
1071
1075
// The symbol for the function name itself has to be evaluated
1072
1076
// at the end to match the runtime evaluation of parameter defaults
1073
1077
// and return-type annotations.
1074
- let symbol = self . add_symbol ( name. id . clone ( ) ) ;
1078
+ let ( symbol, _ ) = self . add_symbol ( name. id . clone ( ) ) ;
1075
1079
self . add_definition ( symbol, function_def) ;
1076
1080
}
1077
1081
ast:: Stmt :: ClassDef ( class) => {
@@ -1095,11 +1099,11 @@ where
1095
1099
) ;
1096
1100
1097
1101
// In Python runtime semantics, a class is registered after its scope is evaluated.
1098
- let symbol = self . add_symbol ( class. name . id . clone ( ) ) ;
1102
+ let ( symbol, _ ) = self . add_symbol ( class. name . id . clone ( ) ) ;
1099
1103
self . add_definition ( symbol, class) ;
1100
1104
}
1101
1105
ast:: Stmt :: TypeAlias ( type_alias) => {
1102
- let symbol = self . add_symbol (
1106
+ let ( symbol, _ ) = self . add_symbol (
1103
1107
type_alias
1104
1108
. name
1105
1109
. as_name_expr ( )
@@ -1133,7 +1137,7 @@ where
1133
1137
( Name :: new ( alias. name . id . split ( '.' ) . next ( ) . unwrap ( ) ) , false )
1134
1138
} ;
1135
1139
1136
- let symbol = self . add_symbol ( symbol_name) ;
1140
+ let ( symbol, _ ) = self . add_symbol ( symbol_name) ;
1137
1141
self . add_definition (
1138
1142
symbol,
1139
1143
ImportDefinitionNodeRef {
@@ -1200,7 +1204,7 @@ where
1200
1204
//
1201
1205
// For more details, see the doc-comment on `StarImportPlaceholderPredicate`.
1202
1206
for export in exported_names ( self . db , referenced_module) {
1203
- let symbol_id = self . add_symbol ( export. clone ( ) ) ;
1207
+ let ( symbol_id, newly_added ) = self . add_symbol ( export. clone ( ) ) ;
1204
1208
let node_ref = StarImportDefinitionNodeRef { node, symbol_id } ;
1205
1209
let star_import = StarImportPlaceholderPredicate :: new (
1206
1210
self . db ,
@@ -1210,13 +1214,38 @@ where
1210
1214
) ;
1211
1215
let pre_definition = self . flow_snapshot ( ) ;
1212
1216
self . push_additional_definition ( symbol_id, node_ref) ;
1213
- let constraint_id =
1214
- self . record_visibility_constraint ( star_import. into ( ) ) ;
1215
- let post_definition = self . flow_snapshot ( ) ;
1216
- self . flow_restore ( pre_definition. clone ( ) ) ;
1217
- self . record_negated_visibility_constraint ( constraint_id) ;
1218
- self . flow_merge ( post_definition) ;
1219
- self . simplify_visibility_constraints ( pre_definition) ;
1217
+
1218
+ // Fast path for if there were no previous definitions
1219
+ // of the symbol defined through the `*` import:
1220
+ // we can apply the visibility constraint to *only* the added definition,
1221
+ // rather than all definitions
1222
+ if newly_added {
1223
+ let constraint_id = self
1224
+ . current_use_def_map_mut ( )
1225
+ . record_star_import_visibility_constraint (
1226
+ star_import,
1227
+ symbol_id,
1228
+ ) ;
1229
+
1230
+ let post_definition = self . flow_snapshot ( ) ;
1231
+ self . flow_restore ( pre_definition) ;
1232
+
1233
+ self . current_use_def_map_mut ( )
1234
+ . negate_star_import_visibility_constraint (
1235
+ symbol_id,
1236
+ constraint_id,
1237
+ ) ;
1238
+
1239
+ self . flow_merge ( post_definition) ;
1240
+ } else {
1241
+ let constraint_id =
1242
+ self . record_visibility_constraint ( star_import. into ( ) ) ;
1243
+ let post_definition = self . flow_snapshot ( ) ;
1244
+ self . flow_restore ( pre_definition. clone ( ) ) ;
1245
+ self . record_negated_visibility_constraint ( constraint_id) ;
1246
+ self . flow_merge ( post_definition) ;
1247
+ self . simplify_visibility_constraints ( pre_definition) ;
1248
+ }
1220
1249
}
1221
1250
1222
1251
continue ;
@@ -1236,7 +1265,7 @@ where
1236
1265
self . has_future_annotations |= alias. name . id == "annotations"
1237
1266
&& node. module . as_deref ( ) == Some ( "__future__" ) ;
1238
1267
1239
- let symbol = self . add_symbol ( symbol_name. clone ( ) ) ;
1268
+ let ( symbol, _ ) = self . add_symbol ( symbol_name. clone ( ) ) ;
1240
1269
1241
1270
self . add_definition (
1242
1271
symbol,
@@ -1636,7 +1665,7 @@ where
1636
1665
// which is invalid syntax. However, it's still pretty obvious here that the user
1637
1666
// *wanted* `e` to be bound, so we should still create a definition here nonetheless.
1638
1667
if let Some ( symbol_name) = symbol_name {
1639
- let symbol = self . add_symbol ( symbol_name. id . clone ( ) ) ;
1668
+ let ( symbol, _ ) = self . add_symbol ( symbol_name. id . clone ( ) ) ;
1640
1669
1641
1670
self . add_definition (
1642
1671
symbol,
@@ -1721,7 +1750,7 @@ where
1721
1750
( ast:: ExprContext :: Del , _) => ( false , true ) ,
1722
1751
( ast:: ExprContext :: Invalid , _) => ( false , false ) ,
1723
1752
} ;
1724
- let symbol = self . add_symbol ( id. clone ( ) ) ;
1753
+ let ( symbol, _ ) = self . add_symbol ( id. clone ( ) ) ;
1725
1754
1726
1755
if is_use {
1727
1756
self . mark_symbol_used ( symbol) ;
@@ -2007,7 +2036,7 @@ where
2007
2036
range : _,
2008
2037
} ) = pattern
2009
2038
{
2010
- let symbol = self . add_symbol ( name. id ( ) . clone ( ) ) ;
2039
+ let ( symbol, _ ) = self . add_symbol ( name. id ( ) . clone ( ) ) ;
2011
2040
let state = self . current_match_case . as_ref ( ) . unwrap ( ) ;
2012
2041
self . add_definition (
2013
2042
symbol,
@@ -2028,7 +2057,7 @@ where
2028
2057
rest : Some ( name) , ..
2029
2058
} ) = pattern
2030
2059
{
2031
- let symbol = self . add_symbol ( name. id ( ) . clone ( ) ) ;
2060
+ let ( symbol, _ ) = self . add_symbol ( name. id ( ) . clone ( ) ) ;
2032
2061
let state = self . current_match_case . as_ref ( ) . unwrap ( ) ;
2033
2062
self . add_definition (
2034
2063
symbol,
0 commit comments