@@ -472,12 +472,56 @@ pub(crate) fn place_from_declarations<'db>(
472472 place_from_declarations_impl ( db, declarations, RequiresExplicitReExport :: No )
473473}
474474
475- pub ( crate ) type DeclaredTypeAndConflictingTypes < ' db > =
476- ( TypeAndQualifiers < ' db > , Box < indexmap:: set:: Slice < Type < ' db > > > ) ;
475+ type DeclaredTypeAndConflictingTypes < ' db > = (
476+ TypeAndQualifiers < ' db > ,
477+ Option < Box < indexmap:: set:: Slice < Type < ' db > > > > ,
478+ ) ;
477479
478480/// The result of looking up a declared type from declarations; see [`place_from_declarations`].
479- pub ( crate ) type PlaceFromDeclarationsResult < ' db > =
480- Result < PlaceAndQualifiers < ' db > , DeclaredTypeAndConflictingTypes < ' db > > ;
481+ pub ( crate ) struct PlaceFromDeclarationsResult < ' db > {
482+ place_and_quals : PlaceAndQualifiers < ' db > ,
483+ conflicting_types : Option < Box < indexmap:: set:: Slice < Type < ' db > > > > ,
484+ }
485+
486+ impl < ' db > PlaceFromDeclarationsResult < ' db > {
487+ fn conflict (
488+ place_and_quals : PlaceAndQualifiers < ' db > ,
489+ conflicting_types : Box < indexmap:: set:: Slice < Type < ' db > > > ,
490+ ) -> Self {
491+ PlaceFromDeclarationsResult {
492+ place_and_quals,
493+ conflicting_types : Some ( conflicting_types) ,
494+ }
495+ }
496+
497+ pub ( crate ) fn ignore_conflicting_declarations ( self ) -> PlaceAndQualifiers < ' db > {
498+ self . place_and_quals
499+ }
500+
501+ pub ( crate ) fn with_conflicting_declarations (
502+ self ,
503+ ) -> (
504+ PlaceAndQualifiers < ' db > ,
505+ Option < Box < indexmap:: set:: Slice < Type < ' db > > > > ,
506+ ) {
507+ ( self . place_and_quals , self . conflicting_types )
508+ }
509+ }
510+
511+ impl < ' db > From < PlaceAndQualifiers < ' db > > for PlaceFromDeclarationsResult < ' db > {
512+ fn from ( place_and_quals : PlaceAndQualifiers < ' db > ) -> Self {
513+ PlaceFromDeclarationsResult {
514+ place_and_quals,
515+ conflicting_types : None ,
516+ }
517+ }
518+ }
519+
520+ impl < ' db > From < Place < ' db > > for PlaceFromDeclarationsResult < ' db > {
521+ fn from ( place : Place < ' db > ) -> Self {
522+ PlaceFromDeclarationsResult :: from ( PlaceAndQualifiers :: from ( place) )
523+ }
524+ }
481525
482526/// A type with declaredness information, and a set of type qualifiers.
483527///
@@ -659,7 +703,8 @@ fn place_by_id<'db>(
659703 ConsideredDefinitions :: AllReachable => use_def. all_reachable_declarations ( place_id) ,
660704 } ;
661705
662- let declared = place_from_declarations_impl ( db, declarations, requires_explicit_reexport) ;
706+ let declared = place_from_declarations_impl ( db, declarations, requires_explicit_reexport)
707+ . ignore_conflicting_declarations ( ) ;
663708
664709 let all_considered_bindings = || match considered_definitions {
665710 ConsideredDefinitions :: EndOfScope => use_def. end_of_scope_bindings ( place_id) ,
@@ -668,53 +713,41 @@ fn place_by_id<'db>(
668713
669714 // If a symbol is undeclared, but qualified with `typing.Final`, we use the right-hand side
670715 // inferred type, without unioning with `Unknown`, because it can not be modified.
671- if let Some ( qualifiers) = declared
672- . as_ref ( )
673- . ok ( )
674- . and_then ( PlaceAndQualifiers :: is_bare_final)
675- {
716+ if let Some ( qualifiers) = declared. is_bare_final ( ) {
676717 let bindings = all_considered_bindings ( ) ;
677718 return place_from_bindings_impl ( db, bindings, requires_explicit_reexport)
678719 . with_qualifiers ( qualifiers) ;
679720 }
680721
681- // Handle bare `ClassVar` annotations by falling back to the union of `Unknown` and the
682- // inferred type.
683722 match declared {
684- Ok ( PlaceAndQualifiers {
723+ // Handle bare `ClassVar` annotations by falling back to the union of `Unknown` and the
724+ // inferred type.
725+ PlaceAndQualifiers {
685726 place : Place :: Type ( Type :: Dynamic ( DynamicType :: Unknown ) , declaredness) ,
686727 qualifiers,
687- } ) if qualifiers. contains ( TypeQualifiers :: CLASS_VAR ) => {
728+ } if qualifiers. contains ( TypeQualifiers :: CLASS_VAR ) => {
688729 let bindings = all_considered_bindings ( ) ;
689730 match place_from_bindings_impl ( db, bindings, requires_explicit_reexport) {
690- Place :: Type ( inferred, boundness) => {
691- return Place :: Type (
692- UnionType :: from_elements ( db, [ Type :: unknown ( ) , inferred] ) ,
693- boundness,
694- )
695- . with_qualifiers ( qualifiers) ;
696- }
731+ Place :: Type ( inferred, boundness) => Place :: Type (
732+ UnionType :: from_elements ( db, [ Type :: unknown ( ) , inferred] ) ,
733+ boundness,
734+ )
735+ . with_qualifiers ( qualifiers) ,
697736 Place :: Unbound => {
698- return Place :: Type ( Type :: unknown ( ) , declaredness) . with_qualifiers ( qualifiers) ;
737+ Place :: Type ( Type :: unknown ( ) , declaredness) . with_qualifiers ( qualifiers)
699738 }
700739 }
701740 }
702- _ => { }
703- }
704-
705- match declared {
706741 // Place is declared, trust the declared type
707- Ok (
708- place_and_quals @ PlaceAndQualifiers {
709- place : Place :: Type ( _, Boundness :: Bound ) ,
710- qualifiers : _,
711- } ,
712- ) => place_and_quals,
742+ place_and_quals @ PlaceAndQualifiers {
743+ place : Place :: Type ( _, Boundness :: Bound ) ,
744+ qualifiers : _,
745+ } => place_and_quals,
713746 // Place is possibly declared
714- Ok ( PlaceAndQualifiers {
747+ PlaceAndQualifiers {
715748 place : Place :: Type ( declared_ty, Boundness :: PossiblyUnbound ) ,
716749 qualifiers,
717- } ) => {
750+ } => {
718751 let bindings = all_considered_bindings ( ) ;
719752 let boundness_analysis = bindings. boundness_analysis ;
720753 let inferred = place_from_bindings_impl ( db, bindings, requires_explicit_reexport) ;
@@ -741,10 +774,10 @@ fn place_by_id<'db>(
741774 PlaceAndQualifiers { place, qualifiers }
742775 }
743776 // Place is undeclared, return the union of `Unknown` with the inferred type
744- Ok ( PlaceAndQualifiers {
777+ PlaceAndQualifiers {
745778 place : Place :: Unbound ,
746779 qualifiers : _,
747- } ) => {
780+ } => {
748781 let bindings = all_considered_bindings ( ) ;
749782 let boundness_analysis = bindings. boundness_analysis ;
750783 let mut inferred = place_from_bindings_impl ( db, bindings, requires_explicit_reexport) ;
@@ -786,12 +819,6 @@ fn place_by_id<'db>(
786819 . into ( )
787820 }
788821 }
789- // Place has conflicting declared types
790- Err ( ( declared, _) ) => {
791- // Intentionally ignore conflicting declared types; that's not our problem,
792- // it's the problem of the module we are importing from.
793- Place :: bound ( declared. inner_type ( ) ) . with_qualifiers ( declared. qualifiers ( ) )
794- }
795822 }
796823
797824 // TODO (ticket: https://github.com/astral-sh/ruff/issues/14297) Our handling of boundness
@@ -1129,18 +1156,20 @@ impl<'db> DeclaredTypeBuilder<'db> {
11291156 }
11301157
11311158 fn build ( mut self ) -> DeclaredTypeAndConflictingTypes < ' db > {
1132- if !self . conflicting_types . is_empty ( ) {
1159+ let type_and_quals = TypeAndQualifiers :: new ( self . inner . build ( ) , self . qualifiers ) ;
1160+ if self . conflicting_types . is_empty ( ) {
1161+ ( type_and_quals, None )
1162+ } else {
11331163 self . conflicting_types . insert_before (
11341164 0 ,
11351165 self . first_type
11361166 . expect ( "there must be a first type if there are conflicting types" ) ,
11371167 ) ;
1168+ (
1169+ type_and_quals,
1170+ Some ( self . conflicting_types . into_boxed_slice ( ) ) ,
1171+ )
11381172 }
1139-
1140- (
1141- TypeAndQualifiers :: new ( self . inner . build ( ) , self . qualifiers ) ,
1142- self . conflicting_types . into_boxed_slice ( ) ,
1143- )
11441173 }
11451174}
11461175
@@ -1203,22 +1232,16 @@ fn place_from_declarations_impl<'db>(
12031232 ) ;
12041233
12051234 if let Some ( first) = types. next ( ) {
1206- let declared = if let Some ( second) = types. next ( ) {
1235+ let ( declared, conflicting ) = if let Some ( second) = types. next ( ) {
12071236 let mut builder = DeclaredTypeBuilder :: new ( db) ;
12081237 builder. add ( first) ;
12091238 builder. add ( second) ;
12101239 for element in types {
12111240 builder. add ( element) ;
12121241 }
1213- let ( union, conflicting) = builder. build ( ) ;
1214-
1215- if !conflicting. is_empty ( ) {
1216- return Err ( ( union, conflicting) ) ;
1217- }
1218-
1219- union
1242+ builder. build ( )
12201243 } else {
1221- first
1244+ ( first, None )
12221245 } ;
12231246
12241247 let boundness = match boundness_analysis {
@@ -1244,9 +1267,16 @@ fn place_from_declarations_impl<'db>(
12441267 } ,
12451268 } ;
12461269
1247- Ok ( Place :: Type ( declared. inner_type ( ) , boundness) . with_qualifiers ( declared. qualifiers ( ) ) )
1270+ let place_and_quals =
1271+ Place :: Type ( declared. inner_type ( ) , boundness) . with_qualifiers ( declared. qualifiers ( ) ) ;
1272+
1273+ if let Some ( conflicting) = conflicting {
1274+ PlaceFromDeclarationsResult :: conflict ( place_and_quals, conflicting)
1275+ } else {
1276+ place_and_quals. into ( )
1277+ }
12481278 } else {
1249- Ok ( Place :: Unbound . into ( ) )
1279+ Place :: Unbound . into ( )
12501280 }
12511281}
12521282
@@ -1281,31 +1311,32 @@ mod implicit_globals {
12811311 use crate :: semantic_index:: { place_table, use_def_map} ;
12821312 use crate :: types:: { KnownClass , Type } ;
12831313
1284- use super :: { Place , PlaceFromDeclarationsResult , place_from_declarations} ;
1314+ use super :: { Place , place_from_declarations} ;
12851315
12861316 pub ( crate ) fn module_type_implicit_global_declaration < ' db > (
12871317 db : & ' db dyn Db ,
12881318 name : & str ,
1289- ) -> PlaceFromDeclarationsResult < ' db > {
1319+ ) -> PlaceAndQualifiers < ' db > {
12901320 if !module_type_symbols ( db)
12911321 . iter ( )
12921322 . any ( |module_type_member| module_type_member == name)
12931323 {
1294- return Ok ( Place :: Unbound . into ( ) ) ;
1324+ return Place :: Unbound . into ( ) ;
12951325 }
12961326 let Type :: ClassLiteral ( module_type_class) = KnownClass :: ModuleType . to_class_literal ( db)
12971327 else {
1298- return Ok ( Place :: Unbound . into ( ) ) ;
1328+ return Place :: Unbound . into ( ) ;
12991329 } ;
13001330 let module_type_scope = module_type_class. body_scope ( db) ;
13011331 let place_table = place_table ( db, module_type_scope) ;
13021332 let Some ( symbol_id) = place_table. symbol_id ( name) else {
1303- return Ok ( Place :: Unbound . into ( ) ) ;
1333+ return Place :: Unbound . into ( ) ;
13041334 } ;
13051335 place_from_declarations (
13061336 db,
13071337 use_def_map ( db, module_type_scope) . end_of_scope_symbol_declarations ( symbol_id) ,
13081338 )
1339+ . ignore_conflicting_declarations ( )
13091340 }
13101341
13111342 /// Looks up the type of an "implicit global symbol". Returns [`Place::Unbound`] if
0 commit comments