@@ -1142,27 +1142,30 @@ impl<'db> Node<'db> {
11421142 /// Invokes a callback for each of the representative types of a particular typevar for this
11431143 /// constraint set.
11441144 ///
1145- /// There is a representative type for each distinct path from the BDD root to the `AlwaysTrue`
1145+ /// We first abstract the BDD so that it only mentions constraints on the requested typevar. We
1146+ /// then invoke your callback for each distinct path from the BDD root to the `AlwaysTrue`
11461147 /// terminal. Each of those paths can be viewed as the conjunction of the individual
11471148 /// constraints of each internal node that we traverse as we walk that path. We provide the
11481149 /// lower/upper bound of this conjunction to your callback, allowing you to choose any suitable
11491150 /// type in the range.
1151+ ///
1152+ /// If the abstracted BDD does not mention the typevar at all (i.e., it leaves the typevar
1153+ /// completely unconstrained), we will invoke your callback once with `None`.
11501154 fn find_representative_types (
11511155 self ,
11521156 db : & ' db dyn Db ,
11531157 bound_typevar : BoundTypeVarIdentity < ' db > ,
1154- mut f : impl FnMut ( Type < ' db > , Type < ' db > ) ,
1158+ mut f : impl FnMut ( Option < ( Type < ' db > , Type < ' db > ) > ) ,
11551159 ) {
11561160 self . retain_one ( db, bound_typevar)
1157- . find_representative_types_inner ( db, Type :: Never , Type :: object ( ) , & mut f) ;
1161+ . find_representative_types_inner ( db, None , & mut f) ;
11581162 }
11591163
11601164 fn find_representative_types_inner (
11611165 self ,
11621166 db : & ' db dyn Db ,
1163- greatest_lower_bound : Type < ' db > ,
1164- least_upper_bound : Type < ' db > ,
1165- f : & mut dyn FnMut ( Type < ' db > , Type < ' db > ) ,
1167+ current_bounds : Option < ( Type < ' db > , Type < ' db > ) > ,
1168+ f : & mut dyn FnMut ( Option < ( Type < ' db > , Type < ' db > ) > ) ,
11661169 ) {
11671170 match self {
11681171 Node :: AlwaysTrue => {
@@ -1172,12 +1175,16 @@ impl<'db> Node<'db> {
11721175 // If `lower ≰ upper`, then this path somehow represents in invalid specialization.
11731176 // That should have been removed from the BDD domain as part of the simplification
11741177 // process.
1175- debug_assert ! ( greatest_lower_bound. is_subtype_of( db, least_upper_bound) ) ;
1178+ debug_assert ! ( current_bounds. is_none_or(
1179+ |( greatest_lower_bound, least_upper_bound) | {
1180+ greatest_lower_bound. is_subtype_of( db, least_upper_bound)
1181+ }
1182+ ) ) ;
11761183
11771184 // We've been tracking the lower and upper bound that the types for this path must
11781185 // satisfy. Pass those bounds along and let the caller choose a representative type
11791186 // from within that range.
1180- f ( greatest_lower_bound , least_upper_bound ) ;
1187+ f ( current_bounds ) ;
11811188 }
11821189
11831190 Node :: AlwaysFalse => {
@@ -1186,6 +1193,9 @@ impl<'db> Node<'db> {
11861193 }
11871194
11881195 Node :: Interior ( interior) => {
1196+ let ( greatest_lower_bound, least_upper_bound) =
1197+ current_bounds. unwrap_or ( ( Type :: Never , Type :: object ( ) ) ) ;
1198+
11891199 // For an interior node, there are two outgoing paths: one for the `if_true`
11901200 // branch, and one for the `if_false` branch.
11911201 //
@@ -1200,8 +1210,7 @@ impl<'db> Node<'db> {
12001210 IntersectionType :: from_elements ( db, [ least_upper_bound, constraint. upper ( db) ] ) ;
12011211 interior. if_true ( db) . find_representative_types_inner (
12021212 db,
1203- new_greatest_lower_bound,
1204- new_least_upper_bound,
1213+ Some ( ( new_greatest_lower_bound, new_least_upper_bound) ) ,
12051214 f,
12061215 ) ;
12071216
@@ -1217,8 +1226,7 @@ impl<'db> Node<'db> {
12171226 // path.
12181227 interior. if_false ( db) . find_representative_types_inner (
12191228 db,
1220- greatest_lower_bound,
1221- least_upper_bound,
1229+ Some ( ( greatest_lower_bound, least_upper_bound) ) ,
12221230 f,
12231231 ) ;
12241232 }
@@ -3128,19 +3136,23 @@ impl<'db> GenericContext<'db> {
31283136 // _each_ of the paths into separate specializations, but it's not clear what we would
31293137 // do with that, so instead we just report the ambiguity as a specialization failure.
31303138 let mut satisfied = false ;
3139+ let mut unconstrained = false ;
31313140 let mut greatest_lower_bound = Type :: Never ;
31323141 let mut least_upper_bound = Type :: object ( ) ;
3133- abstracted. find_representative_types (
3134- db,
3135- bound_typevar. identity ( db) ,
3136- |lower_bound, upper_bound| {
3137- satisfied = true ;
3138- greatest_lower_bound =
3139- UnionType :: from_elements ( db, [ greatest_lower_bound, lower_bound] ) ;
3140- least_upper_bound =
3141- IntersectionType :: from_elements ( db, [ least_upper_bound, upper_bound] ) ;
3142- } ,
3143- ) ;
3142+ abstracted. find_representative_types ( db, bound_typevar. identity ( db) , |bounds| {
3143+ satisfied = true ;
3144+ match bounds {
3145+ Some ( ( lower_bound, upper_bound) ) => {
3146+ greatest_lower_bound =
3147+ UnionType :: from_elements ( db, [ greatest_lower_bound, lower_bound] ) ;
3148+ least_upper_bound =
3149+ IntersectionType :: from_elements ( db, [ least_upper_bound, upper_bound] ) ;
3150+ }
3151+ None => {
3152+ unconstrained = true ;
3153+ }
3154+ }
3155+ } ) ;
31443156
31453157 // If there are no satisfiable paths in the BDD, then there is no valid specialization
31463158 // for this constraint set.
@@ -3150,6 +3162,12 @@ impl<'db> GenericContext<'db> {
31503162 return None ;
31513163 }
31523164
3165+ // The BDD is satisfiable, but the typevar is unconstrained, then we use `None` to tell
3166+ // specialize_recursive to fall back on the typevar's default.
3167+ if unconstrained {
3168+ return None ;
3169+ }
3170+
31533171 // If `lower ≰ upper`, then there is no type that satisfies all of the paths in the
31543172 // BDD. That's an ambiguous specialization, as described above.
31553173 if !greatest_lower_bound. is_subtype_of ( db, least_upper_bound) {
0 commit comments