@@ -661,6 +661,7 @@ fn place_by_id<'db>(
661
661
qualifiers,
662
662
} ) => {
663
663
let bindings = all_considered_bindings ( ) ;
664
+ let boundness_analysis = bindings. boundness_analysis ;
664
665
let inferred = place_from_bindings_impl ( db, bindings, requires_explicit_reexport) ;
665
666
666
667
let place = match inferred {
@@ -674,7 +675,11 @@ fn place_by_id<'db>(
674
675
// Place is possibly undeclared and (possibly) bound
675
676
Place :: Type ( inferred_ty, boundness) => Place :: Type (
676
677
UnionType :: from_elements ( db, [ inferred_ty, declared_ty] ) ,
677
- boundness,
678
+ if boundness_analysis == BoundnessAnalysis :: AlwaysBound {
679
+ Boundness :: Bound
680
+ } else {
681
+ boundness
682
+ } ,
678
683
) ,
679
684
} ;
680
685
@@ -686,7 +691,14 @@ fn place_by_id<'db>(
686
691
qualifiers : _,
687
692
} ) => {
688
693
let bindings = all_considered_bindings ( ) ;
689
- let inferred = place_from_bindings_impl ( db, bindings, requires_explicit_reexport) ;
694
+ let boundness_analysis = bindings. boundness_analysis ;
695
+ let mut inferred = place_from_bindings_impl ( db, bindings, requires_explicit_reexport) ;
696
+
697
+ if boundness_analysis == BoundnessAnalysis :: AlwaysBound {
698
+ if let Place :: Type ( ty, Boundness :: PossiblyUnbound ) = inferred {
699
+ inferred = Place :: Type ( ty, Boundness :: Bound ) ;
700
+ }
701
+ }
690
702
691
703
// `__slots__` is a symbol with special behavior in Python's runtime. It can be
692
704
// modified externally, but those changes do not take effect. We therefore issue
@@ -828,6 +840,7 @@ fn place_from_bindings_impl<'db>(
828
840
} ) if binding. is_undefined_or ( is_non_exported) => Some ( * reachability_constraint) ,
829
841
_ => None ,
830
842
} ;
843
+ let mut all_bindings_definitely_reachable = true ;
831
844
let mut deleted_reachability = Truthiness :: AlwaysFalse ;
832
845
833
846
// Evaluate this lazily because we don't always need it (for example, if there are no visible
@@ -920,13 +933,27 @@ fn place_from_bindings_impl<'db>(
920
933
}
921
934
922
935
let binding_ty = binding_type ( db, binding) ;
936
+ all_bindings_definitely_reachable =
937
+ all_bindings_definitely_reachable && static_reachability. is_always_true ( ) ;
923
938
Some ( narrowing_constraint. narrow ( db, binding_ty, binding. place ( db) ) )
924
939
} ,
925
940
) ;
926
941
927
942
if let Some ( first) = types. next ( ) {
943
+ let ty = if let Some ( second) = types. next ( ) {
944
+ UnionType :: from_elements ( db, [ first, second] . into_iter ( ) . chain ( types) )
945
+ } else {
946
+ first
947
+ } ;
948
+
928
949
let boundness = match boundness_analysis {
929
- BoundnessAnalysis :: AlwaysBound => Boundness :: Bound ,
950
+ BoundnessAnalysis :: AlwaysBound => {
951
+ if all_bindings_definitely_reachable {
952
+ Boundness :: Bound
953
+ } else {
954
+ Boundness :: PossiblyUnbound
955
+ }
956
+ }
930
957
BoundnessAnalysis :: BasedOnUnboundVisibility => match unbound_visibility ( ) {
931
958
Some ( Truthiness :: AlwaysTrue ) => {
932
959
unreachable ! (
@@ -938,11 +965,6 @@ fn place_from_bindings_impl<'db>(
938
965
} ,
939
966
} ;
940
967
941
- let ty = if let Some ( second) = types. next ( ) {
942
- UnionType :: from_elements ( db, [ first, second] . into_iter ( ) . chain ( types) )
943
- } else {
944
- first
945
- } ;
946
968
match deleted_reachability {
947
969
Truthiness :: AlwaysFalse => Place :: Type ( ty, boundness) ,
948
970
Truthiness :: AlwaysTrue => Place :: Unbound ,
@@ -1066,6 +1088,8 @@ fn place_from_declarations_impl<'db>(
1066
1088
_ => Truthiness :: AlwaysFalse ,
1067
1089
} ;
1068
1090
1091
+ let mut all_declarations_definitely_reachable = true ;
1092
+
1069
1093
let types = declarations. filter_map (
1070
1094
|DeclarationWithConstraint {
1071
1095
declaration,
@@ -1085,6 +1109,9 @@ fn place_from_declarations_impl<'db>(
1085
1109
if static_reachability. is_always_false ( ) {
1086
1110
None
1087
1111
} else {
1112
+ all_declarations_definitely_reachable =
1113
+ all_declarations_definitely_reachable && static_reachability. is_always_true ( ) ;
1114
+
1088
1115
Some ( declaration_type ( db, declaration) )
1089
1116
}
1090
1117
} ,
@@ -1104,7 +1131,13 @@ fn place_from_declarations_impl<'db>(
1104
1131
}
1105
1132
1106
1133
let boundness = match boundness_analysis {
1107
- BoundnessAnalysis :: AlwaysBound => Boundness :: Bound ,
1134
+ BoundnessAnalysis :: AlwaysBound => {
1135
+ if all_declarations_definitely_reachable {
1136
+ Boundness :: Bound
1137
+ } else {
1138
+ Boundness :: PossiblyUnbound
1139
+ }
1140
+ }
1108
1141
BoundnessAnalysis :: BasedOnUnboundVisibility => match undeclared_reachability {
1109
1142
Truthiness :: AlwaysTrue => {
1110
1143
unreachable ! (
0 commit comments