1
1
use ruff_db:: files:: File ;
2
+ use salsa:: Update ;
2
3
3
4
use crate :: dunder_all:: dunder_all_names;
4
5
use crate :: module_resolver:: file_to_module;
@@ -202,8 +203,15 @@ pub(crate) fn symbol<'db>(
202
203
db : & ' db dyn Db ,
203
204
scope : ScopeId < ' db > ,
204
205
name : & str ,
206
+ considered_bindings : ConsideredBindings ,
205
207
) -> PlaceAndQualifiers < ' db > {
206
- symbol_impl ( db, scope, name, RequiresExplicitReExport :: No )
208
+ symbol_impl (
209
+ db,
210
+ scope,
211
+ name,
212
+ RequiresExplicitReExport :: No ,
213
+ considered_bindings,
214
+ )
207
215
}
208
216
209
217
/// Infer the public type of a place (its type as seen from outside its scope) in the given
@@ -212,8 +220,15 @@ pub(crate) fn place<'db>(
212
220
db : & ' db dyn Db ,
213
221
scope : ScopeId < ' db > ,
214
222
expr : & PlaceExpr ,
223
+ considered_bindings : ConsideredBindings ,
215
224
) -> PlaceAndQualifiers < ' db > {
216
- place_impl ( db, scope, expr, RequiresExplicitReExport :: No )
225
+ place_impl (
226
+ db,
227
+ scope,
228
+ expr,
229
+ RequiresExplicitReExport :: No ,
230
+ considered_bindings,
231
+ )
217
232
}
218
233
219
234
/// Infer the public type of a class symbol (its type as seen from outside its scope) in the given
@@ -226,7 +241,13 @@ pub(crate) fn class_symbol<'db>(
226
241
place_table ( db, scope)
227
242
. place_id_by_name ( name)
228
243
. map ( |symbol| {
229
- let symbol_and_quals = place_by_id ( db, scope, symbol, RequiresExplicitReExport :: No ) ;
244
+ let symbol_and_quals = place_by_id (
245
+ db,
246
+ scope,
247
+ symbol,
248
+ RequiresExplicitReExport :: No ,
249
+ ConsideredBindings :: LiveBindingsAtUse ,
250
+ ) ;
230
251
231
252
if symbol_and_quals. is_class_var ( ) {
232
253
// For declared class vars we do not need to check if they have bindings,
@@ -241,8 +262,13 @@ pub(crate) fn class_symbol<'db>(
241
262
{
242
263
// Otherwise, we need to check if the symbol has bindings
243
264
let use_def = use_def_map ( db, scope) ;
244
- let bindings = use_def. public_bindings ( symbol) ;
245
- let inferred = place_from_bindings_impl ( db, bindings, RequiresExplicitReExport :: No ) ;
265
+ let bindings = use_def. end_of_scope_bindings ( symbol) ;
266
+ let inferred = place_from_bindings_impl (
267
+ db,
268
+ bindings,
269
+ RequiresExplicitReExport :: No ,
270
+ ConsideredBindings :: LiveBindingsAtUse ,
271
+ ) ;
246
272
247
273
// TODO: we should not need to calculate inferred type second time. This is a temporary
248
274
// solution until the notion of Boundness and Declaredness is split. See #16036, #16264
@@ -277,6 +303,7 @@ pub(crate) fn explicit_global_symbol<'db>(
277
303
global_scope ( db, file) ,
278
304
name,
279
305
RequiresExplicitReExport :: No ,
306
+ ConsideredBindings :: AllReachable ,
280
307
)
281
308
}
282
309
@@ -330,18 +357,22 @@ pub(crate) fn imported_symbol<'db>(
330
357
// ignore `__getattr__`. Typeshed has a fake `__getattr__` on `types.ModuleType` to help out with
331
358
// dynamic imports; we shouldn't use it for `ModuleLiteral` types where we know exactly which
332
359
// module we're dealing with.
333
- symbol_impl ( db , global_scope ( db , file ) , name , requires_explicit_reexport ) . or_fall_back_to (
360
+ symbol_impl (
334
361
db,
335
- || {
336
- if name == "__getattr__" {
337
- Place :: Unbound . into ( )
338
- } else if name == "__builtins__" {
339
- Place :: bound ( Type :: any ( ) ) . into ( )
340
- } else {
341
- KnownClass :: ModuleType . to_instance ( db) . member ( db, name)
342
- }
343
- } ,
362
+ global_scope ( db, file) ,
363
+ name,
364
+ requires_explicit_reexport,
365
+ ConsideredBindings :: LiveBindingsAtUse ,
344
366
)
367
+ . or_fall_back_to ( db, || {
368
+ if name == "__getattr__" {
369
+ Place :: Unbound . into ( )
370
+ } else if name == "__builtins__" {
371
+ Place :: bound ( Type :: any ( ) ) . into ( )
372
+ } else {
373
+ KnownClass :: ModuleType . to_instance ( db) . member ( db, name)
374
+ }
375
+ } )
345
376
}
346
377
347
378
/// Lookup the type of `symbol` in the builtins namespace.
@@ -361,6 +392,7 @@ pub(crate) fn builtins_symbol<'db>(db: &'db dyn Db, symbol: &str) -> PlaceAndQua
361
392
global_scope ( db, file) ,
362
393
symbol,
363
394
RequiresExplicitReExport :: Yes ,
395
+ ConsideredBindings :: LiveBindingsAtUse ,
364
396
)
365
397
. or_fall_back_to ( db, || {
366
398
// We're looking up in the builtins namespace and not the module, so we should
@@ -431,8 +463,14 @@ fn core_module_scope(db: &dyn Db, core_module: KnownModule) -> Option<ScopeId<'_
431
463
pub ( super ) fn place_from_bindings < ' db > (
432
464
db : & ' db dyn Db ,
433
465
bindings_with_constraints : BindingWithConstraintsIterator < ' _ , ' db > ,
466
+ considered_bindings : ConsideredBindings , // TODO: remove this and always use `LiveBindingsAtUse` here?
434
467
) -> Place < ' db > {
435
- place_from_bindings_impl ( db, bindings_with_constraints, RequiresExplicitReExport :: No )
468
+ place_from_bindings_impl (
469
+ db,
470
+ bindings_with_constraints,
471
+ RequiresExplicitReExport :: No ,
472
+ considered_bindings,
473
+ )
436
474
}
437
475
438
476
/// Build a declared type from a [`DeclarationsIterator`].
@@ -581,6 +619,7 @@ fn place_cycle_recover<'db>(
581
619
_scope : ScopeId < ' db > ,
582
620
_place_id : ScopedPlaceId ,
583
621
_requires_explicit_reexport : RequiresExplicitReExport ,
622
+ _considered_bindings : ConsideredBindings ,
584
623
) -> salsa:: CycleRecoveryAction < PlaceAndQualifiers < ' db > > {
585
624
salsa:: CycleRecoveryAction :: Iterate
586
625
}
@@ -590,6 +629,7 @@ fn place_cycle_initial<'db>(
590
629
_scope : ScopeId < ' db > ,
591
630
_place_id : ScopedPlaceId ,
592
631
_requires_explicit_reexport : RequiresExplicitReExport ,
632
+ _considered_bindings : ConsideredBindings ,
593
633
) -> PlaceAndQualifiers < ' db > {
594
634
Place :: bound ( Type :: Never ) . into ( )
595
635
}
@@ -600,6 +640,7 @@ fn place_by_id<'db>(
600
640
scope : ScopeId < ' db > ,
601
641
place_id : ScopedPlaceId ,
602
642
requires_explicit_reexport : RequiresExplicitReExport ,
643
+ considered_bindings : ConsideredBindings ,
603
644
) -> PlaceAndQualifiers < ' db > {
604
645
let use_def = use_def_map ( db, scope) ;
605
646
@@ -609,6 +650,11 @@ fn place_by_id<'db>(
609
650
let declarations = use_def. public_declarations ( place_id) ;
610
651
let declared = place_from_declarations_impl ( db, declarations, requires_explicit_reexport) ;
611
652
653
+ let all_considered_bindings = || match considered_bindings {
654
+ ConsideredBindings :: LiveBindingsAtUse => use_def. end_of_scope_bindings ( place_id) ,
655
+ ConsideredBindings :: AllReachable => use_def. potentially_reachable_bindings ( place_id) ,
656
+ } ;
657
+
612
658
match declared {
613
659
// Place is declared, trust the declared type
614
660
Ok (
@@ -622,8 +668,13 @@ fn place_by_id<'db>(
622
668
place : Place :: Type ( declared_ty, Boundness :: PossiblyUnbound ) ,
623
669
qualifiers,
624
670
} ) => {
625
- let bindings = use_def. all_bindings ( place_id) ;
626
- let inferred = place_from_bindings_impl ( db, bindings, requires_explicit_reexport) ;
671
+ let bindings = all_considered_bindings ( ) ;
672
+ let inferred = place_from_bindings_impl (
673
+ db,
674
+ bindings,
675
+ requires_explicit_reexport,
676
+ considered_bindings,
677
+ ) ;
627
678
628
679
let place = match inferred {
629
680
// Place is possibly undeclared and definitely unbound
@@ -647,8 +698,13 @@ fn place_by_id<'db>(
647
698
place : Place :: Unbound ,
648
699
qualifiers : _,
649
700
} ) => {
650
- let bindings = use_def. all_bindings ( place_id) ;
651
- let inferred = place_from_bindings_impl ( db, bindings, requires_explicit_reexport) ;
701
+ let bindings = all_considered_bindings ( ) ;
702
+ let inferred = place_from_bindings_impl (
703
+ db,
704
+ bindings,
705
+ requires_explicit_reexport,
706
+ considered_bindings,
707
+ ) ;
652
708
653
709
// `__slots__` is a symbol with special behavior in Python's runtime. It can be
654
710
// modified externally, but those changes do not take effect. We therefore issue
@@ -707,6 +763,7 @@ fn symbol_impl<'db>(
707
763
scope : ScopeId < ' db > ,
708
764
name : & str ,
709
765
requires_explicit_reexport : RequiresExplicitReExport ,
766
+ considered_bindings : ConsideredBindings ,
710
767
) -> PlaceAndQualifiers < ' db > {
711
768
let _span = tracing:: trace_span!( "symbol" , ?name) . entered ( ) ;
712
769
@@ -726,7 +783,15 @@ fn symbol_impl<'db>(
726
783
727
784
place_table ( db, scope)
728
785
. place_id_by_name ( name)
729
- . map ( |symbol| place_by_id ( db, scope, symbol, requires_explicit_reexport) )
786
+ . map ( |symbol| {
787
+ place_by_id (
788
+ db,
789
+ scope,
790
+ symbol,
791
+ requires_explicit_reexport,
792
+ considered_bindings,
793
+ )
794
+ } )
730
795
. unwrap_or_default ( )
731
796
}
732
797
@@ -736,12 +801,21 @@ fn place_impl<'db>(
736
801
scope : ScopeId < ' db > ,
737
802
expr : & PlaceExpr ,
738
803
requires_explicit_reexport : RequiresExplicitReExport ,
804
+ considered_bindings : ConsideredBindings ,
739
805
) -> PlaceAndQualifiers < ' db > {
740
806
let _span = tracing:: trace_span!( "place" , ?expr) . entered ( ) ;
741
807
742
808
place_table ( db, scope)
743
809
. place_id_by_expr ( expr)
744
- . map ( |place| place_by_id ( db, scope, place, requires_explicit_reexport) )
810
+ . map ( |place| {
811
+ place_by_id (
812
+ db,
813
+ scope,
814
+ place,
815
+ requires_explicit_reexport,
816
+ considered_bindings,
817
+ )
818
+ } )
745
819
. unwrap_or_default ( )
746
820
}
747
821
@@ -754,6 +828,7 @@ fn place_from_bindings_impl<'db>(
754
828
db : & ' db dyn Db ,
755
829
bindings_with_constraints : BindingWithConstraintsIterator < ' _ , ' db > ,
756
830
requires_explicit_reexport : RequiresExplicitReExport ,
831
+ considered_bindings : ConsideredBindings ,
757
832
) -> Place < ' db > {
758
833
let predicates = bindings_with_constraints. predicates ;
759
834
let reachability_constraints = bindings_with_constraints. reachability_constraints ;
@@ -868,15 +943,24 @@ fn place_from_bindings_impl<'db>(
868
943
) ;
869
944
870
945
if let Some ( first) = types. next ( ) {
871
- let boundness = match unbound_reachability ( ) {
872
- Some ( Truthiness :: AlwaysTrue ) => {
873
- // unreachable!(
874
- // "If we have at least one binding, the implicit `unbound` binding should not be definitely visible"
875
- // )
876
- Boundness :: Bound // TODO
946
+ let boundness = match considered_bindings {
947
+ ConsideredBindings :: AllReachable => {
948
+ // TODO: explain why we do this
949
+ Boundness :: Bound
950
+ }
951
+ ConsideredBindings :: LiveBindingsAtUse => {
952
+ // If we have at least one binding, the implicit `unbound` binding should not be
953
+ // definitely visible.
954
+ match unbound_reachability ( ) {
955
+ Some ( Truthiness :: AlwaysTrue ) => {
956
+ unreachable ! (
957
+ "If we have at least one binding, the implicit `unbound` binding should not be definitely visible"
958
+ )
959
+ }
960
+ Some ( Truthiness :: AlwaysFalse ) | None => Boundness :: Bound ,
961
+ Some ( Truthiness :: Ambiguous ) => Boundness :: PossiblyUnbound ,
962
+ }
877
963
}
878
- Some ( Truthiness :: AlwaysFalse ) | None => Boundness :: Bound ,
879
- Some ( Truthiness :: Ambiguous ) => Boundness :: PossiblyUnbound ,
880
964
} ;
881
965
882
966
let ty = if let Some ( second) = types. next ( ) {
@@ -1166,6 +1250,12 @@ impl RequiresExplicitReExport {
1166
1250
}
1167
1251
}
1168
1252
1253
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash , Update ) ]
1254
+ pub ( crate ) enum ConsideredBindings {
1255
+ AllReachable ,
1256
+ LiveBindingsAtUse ,
1257
+ }
1258
+
1169
1259
/// Computes a possibly-widened type `Unknown | T_inferred` from the inferred type `T_inferred`
1170
1260
/// of a symbol, unless the type is a known-instance type (e.g. `typing.Any`) or the symbol is
1171
1261
/// considered non-modifiable (e.g. when the symbol is `@Final`). We need this for public uses
0 commit comments