@@ -1536,14 +1536,75 @@ impl<'module, 'a> Generator<'module, 'a> {
15361536 return docvec ! [ left_doc, operator, right_doc] ;
15371537 }
15381538
1539+ // For comparison with singleton custom types, ie, one with no fields.
1540+ // If you have some code like this
1541+ // ```gleam
1542+ // pub type Wibble {
1543+ // Wibble
1544+ // Wobble
1545+ // }
1546+
1547+ // pub fn is_wibble(w: Wibble) -> Bool {
1548+ // w == Wibble
1549+ // }
1550+ // ```
1551+ // Instead of `isEqual(w, new Wibble())`, generate `w instanceof Wibble`
1552+ // because the first approach needs to construct a new Wibble, and then call the isEqual function,
1553+ // which supports any shape of data, and so does a lot of extra logic which isn't necessary.
1554+
1555+ if let Some ( doc) = self . singleton_variant_equality ( left, right, should_be_equal) {
1556+ return doc;
1557+ }
1558+
1559+ if let Some ( doc) = self . singleton_variant_equality ( right, left, should_be_equal) {
1560+ return doc;
1561+ }
1562+
15391563 // Other types must be compared using structural equality
15401564 let left =
15411565 self . not_in_tail_position ( Some ( Ordering :: Strict ) , |this| this. wrap_expression ( left) ) ;
15421566 let right =
15431567 self . not_in_tail_position ( Some ( Ordering :: Strict ) , |this| this. wrap_expression ( right) ) ;
1568+
15441569 self . prelude_equal_call ( should_be_equal, left, right)
15451570 }
15461571
1572+ fn singleton_variant_equality (
1573+ & mut self ,
1574+ left : & ' a TypedExpr ,
1575+ right : & ' a TypedExpr ,
1576+ should_be_equal : bool ,
1577+ ) -> Option < Document < ' a > > {
1578+ if let TypedExpr :: Var {
1579+ constructor :
1580+ ValueConstructor {
1581+ variant : ValueConstructorVariant :: Record { arity : 0 , name, .. } ,
1582+ ..
1583+ } ,
1584+ ..
1585+ } = right
1586+ {
1587+ let left_doc = self
1588+ . not_in_tail_position ( Some ( Ordering :: Strict ) , |this| this. wrap_expression ( left) ) ;
1589+ Some ( self . singleton_equal ( left_doc, name, should_be_equal) )
1590+ } else {
1591+ None
1592+ }
1593+ }
1594+
1595+ fn singleton_equal (
1596+ & self ,
1597+ value : Document < ' a > ,
1598+ tag : & EcoString ,
1599+ should_be_equal : bool ,
1600+ ) -> Document < ' a > {
1601+ if should_be_equal {
1602+ docvec ! [ value, " instanceof " , tag. to_doc( ) ]
1603+ } else {
1604+ docvec ! [ "!(" , value, " instanceof " , tag. to_doc( ) , ")" ]
1605+ }
1606+ }
1607+
15471608 fn equal_with_doc_operands (
15481609 & mut self ,
15491610 left : Document < ' a > ,
@@ -1966,16 +2027,26 @@ impl<'module, 'a> Generator<'module, 'a> {
19662027 docvec ! [ left, " !== " , right]
19672028 }
19682029
1969- ClauseGuard :: Equals { left, right, .. } => {
1970- let left = self . guard ( left) ;
1971- let right = self . guard ( right) ;
1972- self . prelude_equal_call ( true , left, right)
1973- }
2030+ ClauseGuard :: Equals { left, right, .. }
2031+ | ClauseGuard :: NotEquals { left, right, .. } => {
2032+ let should_be_equal = matches ! ( guard, ClauseGuard :: Equals { .. } ) ;
2033+
2034+ // Handle singleton equality optimization for guards
2035+ if let Some ( doc) =
2036+ self . singleton_variant_guard_equality ( left, right, should_be_equal)
2037+ {
2038+ return doc;
2039+ }
19742040
1975- ClauseGuard :: NotEquals { left, right, .. } => {
1976- let left = self . guard ( left) ;
1977- let right = self . guard ( right) ;
1978- self . prelude_equal_call ( false , left, right)
2041+ if let Some ( doc) =
2042+ self . singleton_variant_guard_equality ( right, left, should_be_equal)
2043+ {
2044+ return doc;
2045+ }
2046+
2047+ let left_doc = self . guard ( left) ;
2048+ let right_doc = self . guard ( right) ;
2049+ self . prelude_equal_call ( should_be_equal, left_doc, right_doc)
19792050 }
19802051
19812052 ClauseGuard :: GtFloat { left, right, .. } | ClauseGuard :: GtInt { left, right, .. } => {
@@ -2078,6 +2149,25 @@ impl<'module, 'a> Generator<'module, 'a> {
20782149 }
20792150 }
20802151
2152+ fn singleton_variant_guard_equality (
2153+ & mut self ,
2154+ left : & ' a TypedClauseGuard ,
2155+ right : & ' a TypedClauseGuard ,
2156+ should_be_equal : bool ,
2157+ ) -> Option < Document < ' a > > {
2158+ if let ClauseGuard :: Constant ( Constant :: Record {
2159+ record_constructor : Some ( constructor) ,
2160+ name,
2161+ ..
2162+ } ) = right
2163+ && let ValueConstructorVariant :: Record { arity : 0 , .. } = constructor. variant
2164+ {
2165+ let left_doc = self . guard ( left) ;
2166+ return Some ( self . singleton_equal ( left_doc, name, should_be_equal) ) ;
2167+ }
2168+ None
2169+ }
2170+
20812171 fn wrapped_guard ( & mut self , guard : & ' a TypedClauseGuard ) -> Document < ' a > {
20822172 match guard {
20832173 ClauseGuard :: Var { .. }
0 commit comments