@@ -444,93 +444,96 @@ impl<'db> UnionBuilder<'db> {
444
444
. filter_map ( UnionElement :: to_type_element)
445
445
. any ( |ty| Type :: EnumLiteral ( enum_member_to_add) . is_subtype_of ( self . db , ty) )
446
446
{
447
- self . elements
448
- . push ( UnionElement :: Type ( Type :: EnumLiteral ( enum_member_to_add) ) ) ;
447
+ self . push_type ( Type :: EnumLiteral ( enum_member_to_add) , seen_aliases) ;
449
448
}
450
449
}
451
450
// Adding `object` to a union results in `object`.
452
451
ty if ty. is_object ( self . db ) => {
453
452
self . collapse_to_object ( ) ;
454
453
}
455
454
_ => {
456
- let bool_pair = if let Type :: BooleanLiteral ( b) = ty {
457
- Some ( Type :: BooleanLiteral ( !b) )
458
- } else {
459
- None
460
- } ;
455
+ self . push_type ( ty, seen_aliases) ;
456
+ }
457
+ }
458
+ }
461
459
462
- // If an alias gets here, it means we aren't unpacking aliases, and we also
463
- // shouldn't try to simplify aliases out of the union, because that will require
464
- // unpacking them.
465
- let should_simplify_full = !matches ! ( ty, Type :: TypeAlias ( _) ) ;
460
+ fn push_type ( & mut self , ty : Type < ' db > , seen_aliases : & mut Vec < Type < ' db > > ) {
461
+ let bool_pair = if let Type :: BooleanLiteral ( b) = ty {
462
+ Some ( Type :: BooleanLiteral ( !b) )
463
+ } else {
464
+ None
465
+ } ;
466
466
467
- let mut to_remove = SmallVec :: < [ usize ; 2 ] > :: new ( ) ;
468
- let ty_negated = if should_simplify_full {
469
- ty. negate ( self . db )
470
- } else {
471
- Type :: Never // won't be used
472
- } ;
467
+ // If an alias gets here, it means we aren't unpacking aliases, and we also
468
+ // shouldn't try to simplify aliases out of the union, because that will require
469
+ // unpacking them.
470
+ let should_simplify_full = !matches ! ( ty, Type :: TypeAlias ( _) ) ;
473
471
474
- for ( index, element) in self . elements . iter_mut ( ) . enumerate ( ) {
475
- let element_type = match element. try_reduce ( self . db , ty) {
476
- ReduceResult :: KeepIf ( keep) => {
477
- if !keep {
478
- to_remove. push ( index) ;
479
- }
480
- continue ;
481
- }
482
- ReduceResult :: Type ( ty) => ty,
483
- ReduceResult :: CollapseToObject => {
484
- self . collapse_to_object ( ) ;
485
- return ;
486
- }
487
- ReduceResult :: Ignore => {
488
- return ;
489
- }
490
- } ;
472
+ let mut to_remove = SmallVec :: < [ usize ; 2 ] > :: new ( ) ;
473
+ let ty_negated = if should_simplify_full {
474
+ ty. negate ( self . db )
475
+ } else {
476
+ Type :: Never // won't be used
477
+ } ;
491
478
492
- if ty == element_type {
493
- return ;
479
+ for ( index, element) in self . elements . iter_mut ( ) . enumerate ( ) {
480
+ let element_type = match element. try_reduce ( self . db , ty) {
481
+ ReduceResult :: KeepIf ( keep) => {
482
+ if !keep {
483
+ to_remove. push ( index) ;
494
484
}
485
+ continue ;
486
+ }
487
+ ReduceResult :: Type ( ty) => ty,
488
+ ReduceResult :: CollapseToObject => {
489
+ self . collapse_to_object ( ) ;
490
+ return ;
491
+ }
492
+ ReduceResult :: Ignore => {
493
+ return ;
494
+ }
495
+ } ;
495
496
496
- if Some ( element_type) == bool_pair {
497
- self . add_in_place_impl ( KnownClass :: Bool . to_instance ( self . db ) , seen_aliases) ;
498
- return ;
499
- }
497
+ if ty == element_type {
498
+ return ;
499
+ }
500
500
501
- if should_simplify_full && !matches ! ( element_type, Type :: TypeAlias ( _) ) {
502
- if ty. is_equivalent_to ( self . db , element_type)
503
- || ty. is_subtype_of ( self . db , element_type)
504
- {
505
- return ;
506
- } else if element_type. is_subtype_of ( self . db , ty) {
507
- to_remove. push ( index) ;
508
- } else if ty_negated. is_subtype_of ( self . db , element_type) {
509
- // We add `ty` to the union. We just checked that `~ty` is a subtype of an
510
- // existing `element`. This also means that `~ty | ty` is a subtype of
511
- // `element | ty`, because both elements in the first union are subtypes of
512
- // the corresponding elements in the second union. But `~ty | ty` is just
513
- // `object`. Since `object` is a subtype of `element | ty`, we can only
514
- // conclude that `element | ty` must be `object` (object has no other
515
- // supertypes). This means we can simplify the whole union to just
516
- // `object`, since all other potential elements would also be subtypes of
517
- // `object`.
518
- self . collapse_to_object ( ) ;
519
- return ;
520
- }
521
- }
522
- }
523
- if let Some ( ( & first, rest) ) = to_remove. split_first ( ) {
524
- self . elements [ first] = UnionElement :: Type ( ty) ;
525
- // We iterate in descending order to keep remaining indices valid after `swap_remove`.
526
- for & index in rest. iter ( ) . rev ( ) {
527
- self . elements . swap_remove ( index) ;
528
- }
529
- } else {
530
- self . elements . push ( UnionElement :: Type ( ty) ) ;
501
+ if Some ( element_type) == bool_pair {
502
+ self . add_in_place_impl ( KnownClass :: Bool . to_instance ( self . db ) , seen_aliases) ;
503
+ return ;
504
+ }
505
+
506
+ if should_simplify_full && !matches ! ( element_type, Type :: TypeAlias ( _) ) {
507
+ if ty. is_equivalent_to ( self . db , element_type)
508
+ || ty. is_subtype_of ( self . db , element_type)
509
+ {
510
+ return ;
511
+ } else if element_type. is_subtype_of ( self . db , ty) {
512
+ to_remove. push ( index) ;
513
+ } else if ty_negated. is_subtype_of ( self . db , element_type) {
514
+ // We add `ty` to the union. We just checked that `~ty` is a subtype of an
515
+ // existing `element`. This also means that `~ty | ty` is a subtype of
516
+ // `element | ty`, because both elements in the first union are subtypes of
517
+ // the corresponding elements in the second union. But `~ty | ty` is just
518
+ // `object`. Since `object` is a subtype of `element | ty`, we can only
519
+ // conclude that `element | ty` must be `object` (object has no other
520
+ // supertypes). This means we can simplify the whole union to just
521
+ // `object`, since all other potential elements would also be subtypes of
522
+ // `object`.
523
+ self . collapse_to_object ( ) ;
524
+ return ;
531
525
}
532
526
}
533
527
}
528
+ if let Some ( ( & first, rest) ) = to_remove. split_first ( ) {
529
+ self . elements [ first] = UnionElement :: Type ( ty) ;
530
+ // We iterate in descending order to keep remaining indices valid after `swap_remove`.
531
+ for & index in rest. iter ( ) . rev ( ) {
532
+ self . elements . swap_remove ( index) ;
533
+ }
534
+ } else {
535
+ self . elements . push ( UnionElement :: Type ( ty) ) ;
536
+ }
534
537
}
535
538
536
539
pub ( crate ) fn build ( self ) -> Type < ' db > {
0 commit comments