@@ -9,6 +9,8 @@ use std::borrow::Cow;
99use std:: cmp:: Ordering ;
1010use std:: fmt;
1111use std:: fmt:: Display ;
12+ use std:: hash:: Hash ;
13+ use std:: hash:: Hasher ;
1214use std:: sync:: Arc ;
1315
1416use dupe:: Dupe ;
@@ -611,6 +613,40 @@ pub enum SuperObj {
611613 Class ( ClassType ) ,
612614}
613615
616+ #[ derive( Debug , Clone , Eq , TypeEq , PartialOrd , Ord ) ]
617+ pub struct Union {
618+ pub members : Vec < Type > ,
619+ pub display_name : Option < String > ,
620+ }
621+
622+ impl PartialEq for Union {
623+ fn eq ( & self , other : & Self ) -> bool {
624+ self . members == other. members
625+ }
626+ }
627+
628+ impl Hash for Union {
629+ fn hash < H : Hasher > ( & self , state : & mut H ) {
630+ self . members . hash ( state)
631+ }
632+ }
633+
634+ impl Visit < Type > for Union {
635+ fn recurse < ' a > ( & ' a self , f : & mut dyn FnMut ( & ' a Type ) ) {
636+ for member in & self . members {
637+ member. visit ( f) ;
638+ }
639+ }
640+ }
641+
642+ impl VisitMut < Type > for Union {
643+ fn recurse_mut ( & mut self , f : & mut dyn FnMut ( & mut Type ) ) {
644+ for member in & mut self . members {
645+ member. visit_mut ( f) ;
646+ }
647+ }
648+ }
649+
614650// Note: The fact that Literal and LiteralString are at the front is important for
615651// optimisations in `unions_with_literals`.
616652#[ derive( Debug , Clone , PartialEq , Eq , TypeEq , PartialOrd , Ord , Hash ) ]
@@ -626,7 +662,8 @@ pub enum Type {
626662 BoundMethod ( Box < BoundMethod > ) ,
627663 /// An overloaded function.
628664 Overload ( Overload ) ,
629- Union ( Vec < Type > ) ,
665+ /// Unions will hold an optional name to use when displaying the type
666+ Union ( Box < Union > ) ,
630667 /// Our intersection support is partial, so we store a fallback type that we use for operations
631668 /// that are not yet supported on intersections.
632669 Intersect ( Box < ( Vec < Type > , Type ) > ) ,
@@ -1392,7 +1429,7 @@ impl Type {
13921429 /// type[a | b] -> type[a] | type[b]
13931430 pub fn distribute_type_over_union ( self ) -> Self {
13941431 self . transform ( & mut |ty| {
1395- if let Type :: Type ( box Type :: Union ( members) ) = ty {
1432+ if let Type :: Type ( box Type :: Union ( box Union { members, .. } ) ) = ty {
13961433 * ty = unions ( members. drain ( ..) . map ( Type :: type_form) . collect ( ) ) ;
13971434 }
13981435 } )
@@ -1437,7 +1474,7 @@ impl Type {
14371474
14381475 pub fn sort_unions ( self ) -> Self {
14391476 self . transform ( & mut |ty| {
1440- if let Type :: Union ( ts ) = ty {
1477+ if let Type :: Union ( box Union { members : ts , .. } ) = ty {
14411478 ts. sort ( ) ;
14421479 }
14431480 } )
@@ -1488,27 +1525,30 @@ impl Type {
14881525
14891526 pub fn into_unions ( self ) -> Vec < Type > {
14901527 match self {
1491- Type :: Union ( types) => types,
1528+ Type :: Union ( box Union { members : types, .. } ) => types,
14921529 _ => vec ! [ self ] ,
14931530 }
14941531 }
14951532
14961533 /// Create an optional type (union with None).
14971534 pub fn optional ( x : Self ) -> Self {
14981535 // We would like the resulting type not nested, and well sorted.
1499- if let Type :: Union ( mut xs) = x {
1536+ if let Type :: Union ( box Union {
1537+ members : mut xs, ..
1538+ } ) = x
1539+ {
15001540 match xs. binary_search ( & Type :: None ) {
1501- Ok ( _) => Type :: Union ( xs) ,
1541+ Ok ( _) => Type :: union ( xs) ,
15021542 Err ( i) => {
15031543 xs. insert ( i, Type :: None ) ;
1504- Type :: Union ( xs)
1544+ Type :: union ( xs)
15051545 }
15061546 }
15071547 } else {
15081548 match x. cmp ( & Type :: None ) {
15091549 Ordering :: Equal => Type :: None ,
1510- Ordering :: Less => Type :: Union ( vec ! [ x, Type :: None ] ) ,
1511- Ordering :: Greater => Type :: Union ( vec ! [ Type :: None , x] ) ,
1550+ Ordering :: Less => Type :: union ( vec ! [ x, Type :: None ] ) ,
1551+ Ordering :: Greater => Type :: union ( vec ! [ Type :: None , x] ) ,
15121552 }
15131553 }
15141554 }
@@ -1538,9 +1578,9 @@ impl Type {
15381578 Type :: Literal ( Lit :: Str ( x) ) => Some ( !x. is_empty ( ) ) ,
15391579 Type :: None => Some ( false ) ,
15401580 Type :: Tuple ( Tuple :: Concrete ( elements) ) => Some ( !elements. is_empty ( ) ) ,
1541- Type :: Union ( options ) => {
1581+ Type :: Union ( box Union { members , .. } ) => {
15421582 let mut answer = None ;
1543- for option in options {
1583+ for option in members {
15441584 let option_bool = option. as_bool ( ) ;
15451585 option_bool?;
15461586 if answer. is_none ( ) {
@@ -1590,6 +1630,14 @@ impl Type {
15901630 } )
15911631 } )
15921632 }
1633+
1634+ /// Creates a union from the provided types without simplifying
1635+ pub fn union ( members : Vec < Type > ) -> Self {
1636+ Type :: Union ( Box :: new ( Union {
1637+ members,
1638+ display_name : None ,
1639+ } ) )
1640+ }
15931641}
15941642
15951643#[ cfg( test) ]
@@ -1616,8 +1664,8 @@ mod tests {
16161664 let false_lit = Type :: Literal ( Lit :: Bool ( false ) ) ;
16171665 let none = Type :: None ;
16181666
1619- let str_opt = Type :: Union ( vec ! [ s, none. clone( ) ] ) ;
1620- let false_opt = Type :: Union ( vec ! [ false_lit, none] ) ;
1667+ let str_opt = Type :: union ( vec ! [ s, none. clone( ) ] ) ;
1668+ let false_opt = Type :: union ( vec ! [ false_lit, none] ) ;
16211669
16221670 assert_eq ! ( str_opt. as_bool( ) , None ) ;
16231671 assert_eq ! ( false_opt. as_bool( ) , Some ( false ) ) ;
0 commit comments