@@ -811,6 +811,47 @@ impl<'db> Type<'db> {
811811 }
812812 }
813813
814+ #[ must_use]
815+ pub fn with_normalized_bools ( self , db : & ' db dyn Db ) -> Self {
816+ const LITERAL_BOOLS : [ Type ; 2 ] = [ Type :: BooleanLiteral ( false ) , Type :: BooleanLiteral ( true ) ] ;
817+
818+ match self {
819+ Type :: Instance ( InstanceType { class } ) if class. is_known ( db, KnownClass :: Bool ) => {
820+ Type :: Union ( UnionType :: new ( db, Box :: from ( LITERAL_BOOLS ) ) )
821+ }
822+ // TODO: decompose `LiteralString` into `Literal[""] | TruthyLiteralString`?
823+ // We'd need to rename this method... --Alex
824+ _ => self ,
825+ }
826+ }
827+
828+ #[ must_use]
829+ pub fn with_sorted_unions ( self , db : & ' db dyn Db ) -> Self {
830+ match self {
831+ Type :: Union ( union) => Type :: Union ( union. to_sorted_union ( db) ) ,
832+ Type :: Intersection ( intersection) => {
833+ Type :: Intersection ( intersection. to_sorted_intersection ( db) )
834+ }
835+ Type :: Tuple ( tuple) => Type :: Tuple ( tuple. with_sorted_unions ( db) ) ,
836+ Type :: LiteralString
837+ | Type :: Instance ( _)
838+ | Type :: AlwaysFalsy
839+ | Type :: AlwaysTruthy
840+ | Type :: BooleanLiteral ( _)
841+ | Type :: SliceLiteral ( _)
842+ | Type :: BytesLiteral ( _)
843+ | Type :: StringLiteral ( _)
844+ | Type :: Dynamic ( _)
845+ | Type :: Never
846+ | Type :: FunctionLiteral ( _)
847+ | Type :: ModuleLiteral ( _)
848+ | Type :: ClassLiteral ( _)
849+ | Type :: KnownInstance ( _)
850+ | Type :: IntLiteral ( _)
851+ | Type :: SubclassOf ( _) => self ,
852+ }
853+ }
854+
814855 /// Return true if this type is a [subtype of] type `target`.
815856 ///
816857 /// This method returns `false` if either `self` or `other` is not fully static.
@@ -830,6 +871,12 @@ impl<'db> Type<'db> {
830871 return true ;
831872 }
832873
874+ let left = self . with_normalized_bools ( db) ;
875+ let right = target. with_normalized_bools ( db) ;
876+ if left != self || right != target {
877+ return left. is_subtype_of ( db, right) ;
878+ }
879+
833880 // Non-fully-static types do not participate in subtyping.
834881 //
835882 // Type `A` can only be a subtype of type `B` if the set of possible runtime objects
@@ -932,7 +979,7 @@ impl<'db> Type<'db> {
932979 KnownClass :: Str . to_instance ( db) . is_subtype_of ( db, target)
933980 }
934981 ( Type :: BooleanLiteral ( _) , _) => {
935- KnownClass :: Bool . to_instance ( db) . is_subtype_of ( db, target)
982+ KnownClass :: Int . to_instance ( db) . is_subtype_of ( db, target)
936983 }
937984 ( Type :: IntLiteral ( _) , _) => KnownClass :: Int . to_instance ( db) . is_subtype_of ( db, target) ,
938985 ( Type :: BytesLiteral ( _) , _) => {
@@ -1048,6 +1095,11 @@ impl<'db> Type<'db> {
10481095 if self . is_gradual_equivalent_to ( db, target) {
10491096 return true ;
10501097 }
1098+ let normalized_self = self . with_normalized_bools ( db) ;
1099+ let normalized_target = target. with_normalized_bools ( db) ;
1100+ if normalized_self != self || normalized_target != target {
1101+ return normalized_self. is_assignable_to ( db, normalized_target) ;
1102+ }
10511103 match ( self , target) {
10521104 // Never can be assigned to any type.
10531105 ( Type :: Never , _) => true ,
@@ -1148,13 +1200,20 @@ impl<'db> Type<'db> {
11481200 pub ( crate ) fn is_equivalent_to ( self , db : & ' db dyn Db , other : Type < ' db > ) -> bool {
11491201 // TODO equivalent but not identical types: TypedDicts, Protocols, type aliases, etc.
11501202
1203+ let normalized_self = self . with_normalized_bools ( db) ;
1204+ let normalized_other = other. with_normalized_bools ( db) ;
1205+
1206+ if normalized_self != self || normalized_other != other {
1207+ return normalized_self. is_equivalent_to ( db, normalized_other) ;
1208+ }
1209+
11511210 match ( self , other) {
11521211 ( Type :: Union ( left) , Type :: Union ( right) ) => left. is_equivalent_to ( db, right) ,
11531212 ( Type :: Intersection ( left) , Type :: Intersection ( right) ) => {
11541213 left. is_equivalent_to ( db, right)
11551214 }
11561215 ( Type :: Tuple ( left) , Type :: Tuple ( right) ) => left. is_equivalent_to ( db, right) ,
1157- _ => self . is_fully_static ( db) && other. is_fully_static ( db) && self == other ,
1216+ _ => self == other && self . is_fully_static ( db) && other. is_fully_static ( db) ,
11581217 }
11591218 }
11601219
@@ -1189,6 +1248,13 @@ impl<'db> Type<'db> {
11891248 ///
11901249 /// [Summary of type relations]: https://typing.readthedocs.io/en/latest/spec/concepts.html#summary-of-type-relations
11911250 pub ( crate ) fn is_gradual_equivalent_to ( self , db : & ' db dyn Db , other : Type < ' db > ) -> bool {
1251+ let normalized_self = self . with_normalized_bools ( db) ;
1252+ let normalized_other = other. with_normalized_bools ( db) ;
1253+
1254+ if normalized_self != self || normalized_other != other {
1255+ return normalized_self. is_gradual_equivalent_to ( db, normalized_other) ;
1256+ }
1257+
11921258 if self == other {
11931259 return true ;
11941260 }
@@ -1221,6 +1287,12 @@ impl<'db> Type<'db> {
12211287 /// Note: This function aims to have no false positives, but might return
12221288 /// wrong `false` answers in some cases.
12231289 pub ( crate ) fn is_disjoint_from ( self , db : & ' db dyn Db , other : Type < ' db > ) -> bool {
1290+ let normalized_self = self . with_normalized_bools ( db) ;
1291+ let normalized_other = other. with_normalized_bools ( db) ;
1292+ if normalized_self != self || normalized_other != other {
1293+ return normalized_self. is_disjoint_from ( db, normalized_other) ;
1294+ }
1295+
12241296 match ( self , other) {
12251297 ( Type :: Never , _) | ( _, Type :: Never ) => true ,
12261298
@@ -4352,12 +4424,11 @@ impl<'db> UnionType<'db> {
43524424 /// Create a new union type with the elements sorted according to a canonical ordering.
43534425 #[ must_use]
43544426 pub fn to_sorted_union ( self , db : & ' db dyn Db ) -> Self {
4355- let mut new_elements = self . elements ( db) . to_vec ( ) ;
4356- for element in & mut new_elements {
4357- if let Type :: Intersection ( intersection) = element {
4358- intersection. sort ( db) ;
4359- }
4360- }
4427+ let mut new_elements: Vec < Type < ' db > > = self
4428+ . elements ( db)
4429+ . iter ( )
4430+ . map ( |element| element. with_sorted_unions ( db) )
4431+ . collect ( ) ;
43614432 new_elements. sort_unstable_by ( union_elements_ordering) ;
43624433 UnionType :: new ( db, new_elements. into_boxed_slice ( ) )
43634434 }
@@ -4453,19 +4524,24 @@ impl<'db> IntersectionType<'db> {
44534524 /// according to a canonical ordering.
44544525 #[ must_use]
44554526 pub fn to_sorted_intersection ( self , db : & ' db dyn Db ) -> Self {
4456- let mut positive = self . positive ( db) . clone ( ) ;
4457- positive. sort_unstable_by ( union_elements_ordering) ;
4458-
4459- let mut negative = self . negative ( db) . clone ( ) ;
4460- negative. sort_unstable_by ( union_elements_ordering) ;
4527+ fn normalized_set < ' db > (
4528+ db : & ' db dyn Db ,
4529+ elements : & FxOrderSet < Type < ' db > > ,
4530+ ) -> FxOrderSet < Type < ' db > > {
4531+ let mut elements: FxOrderSet < Type < ' db > > = elements
4532+ . iter ( )
4533+ . map ( |ty| ty. with_sorted_unions ( db) )
4534+ . collect ( ) ;
44614535
4462- IntersectionType :: new ( db, positive, negative)
4463- }
4536+ elements. sort_unstable_by ( union_elements_ordering) ;
4537+ elements
4538+ }
44644539
4465- /// Perform an in-place sort of this [`IntersectionType`] instance
4466- /// according to a canonical ordering.
4467- fn sort ( & mut self , db : & ' db dyn Db ) {
4468- * self = self . to_sorted_intersection ( db) ;
4540+ IntersectionType :: new (
4541+ db,
4542+ normalized_set ( db, self . positive ( db) ) ,
4543+ normalized_set ( db, self . negative ( db) ) ,
4544+ )
44694545 }
44704546
44714547 pub fn is_fully_static ( self , db : & ' db dyn Db ) -> bool {
@@ -4591,23 +4667,34 @@ pub struct TupleType<'db> {
45914667}
45924668
45934669impl < ' db > TupleType < ' db > {
4594- pub fn from_elements < T : Into < Type < ' db > > > (
4595- db : & ' db dyn Db ,
4596- types : impl IntoIterator < Item = T > ,
4597- ) -> Type < ' db > {
4670+ pub fn from_elements < I , T > ( db : & ' db dyn Db , types : I ) -> Type < ' db >
4671+ where
4672+ I : IntoIterator < Item = T > ,
4673+ T : Into < Type < ' db > > ,
4674+ {
45984675 let mut elements = vec ! [ ] ;
45994676
46004677 for ty in types {
4601- let ty = ty. into ( ) ;
4678+ let ty: Type < ' db > = ty. into ( ) ;
46024679 if ty. is_never ( ) {
46034680 return Type :: Never ;
46044681 }
4605- elements. push ( ty) ;
4682+ elements. push ( ty. with_normalized_bools ( db ) ) ;
46064683 }
46074684
46084685 Type :: Tuple ( Self :: new ( db, elements. into_boxed_slice ( ) ) )
46094686 }
46104687
4688+ #[ must_use]
4689+ pub fn with_sorted_unions ( self , db : & ' db dyn Db ) -> Self {
4690+ let elements: Box < [ Type < ' db > ] > = self
4691+ . elements ( db)
4692+ . iter ( )
4693+ . map ( |ty| ty. with_sorted_unions ( db) )
4694+ . collect ( ) ;
4695+ TupleType :: new ( db, elements)
4696+ }
4697+
46114698 pub fn is_equivalent_to ( self , db : & ' db dyn Db , other : Self ) -> bool {
46124699 let self_elements = self . elements ( db) ;
46134700 let other_elements = other. elements ( db) ;
0 commit comments