@@ -388,16 +388,18 @@ impl<'db> Type<'db> {
388
388
}
389
389
}
390
390
391
- /// Return true if this type is [assignable to ] type `target`.
391
+ /// Return true if this type is a [subtype of ] type `target`.
392
392
///
393
- /// [assignable to ]: https://typing.readthedocs.io/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation
394
- pub ( crate ) fn is_assignable_to ( self , db : & ' db dyn Db , target : Type < ' db > ) -> bool {
393
+ /// [subtype of ]: https://typing.readthedocs.io/en/latest/spec/concepts.html#subtype-supertype-and-type-equivalence
394
+ pub ( crate ) fn is_subtype_of ( self , db : & ' db dyn Db , target : Type < ' db > ) -> bool {
395
395
if self . is_equivalent_to ( db, target) {
396
396
return true ;
397
397
}
398
398
match ( self , target) {
399
- ( Type :: Unknown | Type :: Any | Type :: Never , _) => true ,
400
- ( _, Type :: Unknown | Type :: Any ) => true ,
399
+ ( Type :: Unknown | Type :: Any , _) => false ,
400
+ ( _, Type :: Unknown | Type :: Any ) => false ,
401
+ ( Type :: Never , _) => true ,
402
+ ( _, Type :: Never ) => false ,
401
403
( Type :: IntLiteral ( _) , Type :: Instance ( class) )
402
404
if class. is_stdlib_symbol ( db, "builtins" , "int" ) =>
403
405
{
@@ -417,12 +419,28 @@ impl<'db> Type<'db> {
417
419
( ty, Type :: Union ( union) ) => union
418
420
. elements ( db)
419
421
. iter ( )
420
- . any ( |& elem_ty| ty. is_assignable_to ( db, elem_ty) ) ,
422
+ . any ( |& elem_ty| ty. is_subtype_of ( db, elem_ty) ) ,
421
423
// TODO
422
424
_ => false ,
423
425
}
424
426
}
425
427
428
+ /// Return true if this type is [assignable to] type `target`.
429
+ ///
430
+ /// [assignable to]: https://typing.readthedocs.io/en/latest/spec/concepts.html#the-assignable-to-or-consistent-subtyping-relation
431
+ pub ( crate ) fn is_assignable_to ( self , db : & ' db dyn Db , target : Type < ' db > ) -> bool {
432
+ match ( self , target) {
433
+ ( Type :: Unknown | Type :: Any , _) => true ,
434
+ ( _, Type :: Unknown | Type :: Any ) => true ,
435
+ ( ty, Type :: Union ( union) ) => union
436
+ . elements ( db)
437
+ . iter ( )
438
+ . any ( |& elem_ty| ty. is_assignable_to ( db, elem_ty) ) ,
439
+ // TODO other types containing gradual forms (e.g. generics containing Any/Unknown)
440
+ _ => self . is_subtype_of ( db, target) ,
441
+ }
442
+ }
443
+
426
444
/// Return true if this type is equivalent to type `other`.
427
445
pub ( crate ) fn is_equivalent_to ( self , _db : & ' db dyn Db , other : Type < ' db > ) -> bool {
428
446
// TODO equivalent but not identical structural types, differently-ordered unions and
@@ -1132,6 +1150,31 @@ mod tests {
1132
1150
assert ! ( !from. into_type( & db) . is_assignable_to( & db, to. into_type( & db) ) ) ;
1133
1151
}
1134
1152
1153
+ #[ test_case( Ty :: Never , Ty :: IntLiteral ( 1 ) ) ]
1154
+ #[ test_case( Ty :: IntLiteral ( 1 ) , Ty :: BuiltinInstance ( "int" ) ) ]
1155
+ #[ test_case( Ty :: StringLiteral ( "foo" ) , Ty :: BuiltinInstance ( "str" ) ) ]
1156
+ #[ test_case( Ty :: StringLiteral ( "foo" ) , Ty :: LiteralString ) ]
1157
+ #[ test_case( Ty :: LiteralString , Ty :: BuiltinInstance ( "str" ) ) ]
1158
+ #[ test_case( Ty :: BytesLiteral ( "foo" ) , Ty :: BuiltinInstance ( "bytes" ) ) ]
1159
+ #[ test_case( Ty :: IntLiteral ( 1 ) , Ty :: Union ( vec![ Ty :: BuiltinInstance ( "int" ) , Ty :: BuiltinInstance ( "str" ) ] ) ) ]
1160
+ fn is_subtype_of ( from : Ty , to : Ty ) {
1161
+ let db = setup_db ( ) ;
1162
+ assert ! ( from. into_type( & db) . is_subtype_of( & db, to. into_type( & db) ) ) ;
1163
+ }
1164
+
1165
+ #[ test_case( Ty :: Unknown , Ty :: IntLiteral ( 1 ) ) ]
1166
+ #[ test_case( Ty :: Any , Ty :: IntLiteral ( 1 ) ) ]
1167
+ #[ test_case( Ty :: IntLiteral ( 1 ) , Ty :: Unknown ) ]
1168
+ #[ test_case( Ty :: IntLiteral ( 1 ) , Ty :: Any ) ]
1169
+ #[ test_case( Ty :: IntLiteral ( 1 ) , Ty :: Union ( vec![ Ty :: Unknown , Ty :: BuiltinInstance ( "str" ) ] ) ) ]
1170
+ #[ test_case( Ty :: IntLiteral ( 1 ) , Ty :: BuiltinInstance ( "str" ) ) ]
1171
+ #[ test_case( Ty :: BuiltinInstance ( "int" ) , Ty :: BuiltinInstance ( "str" ) ) ]
1172
+ #[ test_case( Ty :: BuiltinInstance ( "int" ) , Ty :: IntLiteral ( 1 ) ) ]
1173
+ fn is_not_subtype_of ( from : Ty , to : Ty ) {
1174
+ let db = setup_db ( ) ;
1175
+ assert ! ( !from. into_type( & db) . is_subtype_of( & db, to. into_type( & db) ) ) ;
1176
+ }
1177
+
1135
1178
#[ test_case(
1136
1179
Ty :: Union ( vec![ Ty :: IntLiteral ( 1 ) , Ty :: IntLiteral ( 2 ) ] ) ,
1137
1180
Ty :: Union ( vec![ Ty :: IntLiteral ( 1 ) , Ty :: IntLiteral ( 2 ) ] )
0 commit comments