module Unison.Runtime.Builtin.Types
  ( typeReferences,
    builtinTypeNumbering,
    builtinTypeBackref,
    anyTypeNumber,
    booleanTypeNumber,
  )
where

import Data.Map qualified as Map
import Unison.Prelude hiding (Text, some)
import Unison.Reference
import Unison.Runtime.Builtin.Decls qualified as Ty
import Unison.Type qualified as Ty
import Unison.Util.EnumContainers as EC

-- | The numbers of the types the runtime tests values against on hot
-- paths (every comparison of two constructors, every boolean read:
-- 'Unison.Runtime.TypeTags.isAnyTag'). They are literals so that the test
-- compares against an immediate, and the numbering below is built from
-- them, so it agrees by construction.
anyTypeNumber, booleanTypeNumber :: Word64
anyTypeNumber :: Word64
anyTypeNumber = Word64
1
{-# INLINE anyTypeNumber #-}
booleanTypeNumber :: Word64
booleanTypeNumber = Word64
2
{-# INLINE booleanTypeNumber #-}

builtinTypeNumbering :: Map Reference Word64
builtinTypeNumbering :: Map Reference Word64
builtinTypeNumbering = [(Reference, Word64)] -> Map Reference Word64
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(Reference, Word64)]
typeReferences

-- | The fixed numbers first, then every other builtin type in order.
typeReferences :: [(Reference, Word64)]
typeReferences :: [(Reference, Word64)]
typeReferences = [(Reference, Word64)]
fixed [(Reference, Word64)]
-> [(Reference, Word64)] -> [(Reference, Word64)]
forall a. [a] -> [a] -> [a]
++ [Reference] -> [Word64] -> [(Reference, Word64)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Reference]
rest [Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral ([(Reference, Word64)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(Reference, Word64)]
fixed) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
+ Word64
1 ..]
  where
    fixed :: [(Reference, Word64)]
fixed = [(Reference
Ty.anyRef, Word64
anyTypeNumber), (Reference
Ty.booleanRef, Word64
booleanTypeNumber)]
    rest :: [Reference]
rest = (Reference -> Bool) -> [Reference] -> [Reference]
forall a. (a -> Bool) -> [a] -> [a]
filter (Reference -> [Reference] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` ((Reference, Word64) -> Reference)
-> [(Reference, Word64)] -> [Reference]
forall a b. (a -> b) -> [a] -> [b]
map (Reference, Word64) -> Reference
forall a b. (a, b) -> a
fst [(Reference, Word64)]
fixed) [Reference]
rs
    rs :: [Reference]
rs =
      [Reference]
Ty.builtinTypeRefs
        [Reference] -> [Reference] -> [Reference]
forall a. [a] -> [a] -> [a]
++ [Reference]
Ty.builtinDataDeclRefs
        [Reference] -> [Reference] -> [Reference]
forall a. [a] -> [a] -> [a]
++ [Reference]
Ty.builtinEffectDeclRefs

builtinTypeBackref :: EnumMap Word64 Reference
builtinTypeBackref :: EnumMap Word64 Reference
builtinTypeBackref = [(Word64, Reference)] -> EnumMap Word64 Reference
forall k a. EnumKey k => [(k, a)] -> EnumMap k a
mapFromList ([(Word64, Reference)] -> EnumMap Word64 Reference)
-> [(Word64, Reference)] -> EnumMap Word64 Reference
forall a b. (a -> b) -> a -> b
$ (Reference, Word64) -> (Word64, Reference)
forall {b} {a}. (b, a) -> (a, b)
swap ((Reference, Word64) -> (Word64, Reference))
-> [(Reference, Word64)] -> [(Word64, Reference)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Reference, Word64)]
typeReferences
  where
    swap :: (b, a) -> (a, b)
swap (b
x, a
y) = (a
y, b
x)