@@ -11,7 +11,7 @@ use crate::types::enums::is_single_member_enum;
1111use crate :: types:: function:: FunctionDecorators ;
1212use crate :: types:: set_theoretic:: RecursivelyDefined ;
1313use crate :: types:: {
14- ApplyTypeMappingVisitor , CallableType , ClassBase , ClassType , CycleDetector ,
14+ ApplyTypeMappingVisitor , CallableType , ClassBase , ClassType , CycleDetector , IntersectionType ,
1515 KnownBoundMethodType , KnownClass , KnownInstanceType , LiteralValueTypeKind , MemberLookupPolicy ,
1616 PropertyInstanceType , ProtocolInstanceType , SubclassOfInner , TypeVarBoundOrConstraints ,
1717 UnionType , UpcastPolicy ,
@@ -710,6 +710,17 @@ impl<'a, 'c, 'db> TypeRelationChecker<'a, 'c, 'db> {
710710 }
711711 }
712712
713+ let should_expand_intersection = |intersection : IntersectionType < ' db > | {
714+ intersection
715+ . positive ( db)
716+ . iter ( )
717+ . any ( |element| match element {
718+ Type :: TypeVar ( tvar) => !tvar. is_inferable ( db, self . inferable ) ,
719+ Type :: NewTypeInstance ( newtype) => newtype. concrete_base_type ( db) . is_union ( ) ,
720+ _ => false ,
721+ } )
722+ } ;
723+
713724 match ( source, target) {
714725 // Everything is a subtype of `object`.
715726 ( _, Type :: NominalInstance ( target) ) if target. is_object ( ) => self . always ( ) ,
@@ -996,25 +1007,18 @@ impl<'a, 'c, 'db> TypeRelationChecker<'a, 'c, 'db> {
9961007 . or ( db, self . constraints , || {
9971008 // Normally non-unions cannot directly contain unions in our model due to the fact that we
9981009 // enforce a DNF structure on our set-theoretic types. However, it *is* possible for there
999- // to be a newtype of a union, or for an intersection to contain a newtype of a union; this
1000- // requires special handling.
1010+ // to be a newtype of a union, for an intersection to contain a newtype of a union, or for
1011+ // a non-inferable typevar (possibly inside an intersection) to widen to a bound or set of
1012+ // constraints that exposes a union; this requires special handling.
10011013 match source {
1002- Type :: Intersection ( intersection) => {
1003- if intersection. positive ( db) . iter ( ) . any ( |& element| {
1004- element. as_new_type ( ) . is_some_and ( |newtype| {
1005- newtype. concrete_base_type ( db) . is_union ( )
1006- } )
1007- } ) {
1008- let mapped = intersection. map_positive ( db, |& t| match t {
1009- Type :: NewTypeInstance ( newtype) => {
1010- newtype. concrete_base_type ( db)
1011- }
1012- _ => t,
1013- } ) ;
1014- self . check_type_pair ( db, mapped, target)
1015- } else {
1016- self . never ( )
1017- }
1014+ Type :: Intersection ( intersection)
1015+ if should_expand_intersection ( intersection) =>
1016+ {
1017+ self . check_type_pair (
1018+ db,
1019+ intersection. with_expanded_typevars_and_newtypes ( db) ,
1020+ target,
1021+ )
10181022 }
10191023 Type :: NewTypeInstance ( newtype) => {
10201024 let concrete_base = newtype. concrete_base_type ( db) ;
@@ -1082,11 +1086,22 @@ impl<'a, 'c, 'db> TypeRelationChecker<'a, 'c, 'db> {
10821086 // positive elements is a subtype of that type. If there are no positive elements,
10831087 // we treat `object` as the implicit positive element (e.g., `~str` is semantically
10841088 // `object & ~str`).
1085- intersection. positive_elements_or_object ( db) . when_any (
1086- db,
1087- self . constraints ,
1088- |elem_ty| self . check_type_pair ( db, elem_ty, target) ,
1089- )
1089+ intersection
1090+ . positive_elements_or_object ( db)
1091+ . when_any ( db, self . constraints , |elem_ty| {
1092+ self . check_type_pair ( db, elem_ty, target)
1093+ } )
1094+ . or ( db, self . constraints , || {
1095+ if should_expand_intersection ( intersection) {
1096+ self . check_type_pair (
1097+ db,
1098+ intersection. with_expanded_typevars_and_newtypes ( db) ,
1099+ target,
1100+ )
1101+ } else {
1102+ self . never ( )
1103+ }
1104+ } )
10901105 }
10911106
10921107 // `Never` is the bottom type, the empty set.
0 commit comments