{-# LANGUAGE KindSignatures, TypeInType, TypeFamilies, TypeOperators, UndecidableInstances #-} module Clr.Resolver.BetterConversion (IsBetterConv) where import Clr.Resolver.ImplicitConversions import Clr.ListTuple import Clr.Types import Data.Kind import GHC.TypeLits import Data.Type.Bool import Data.Type.Equality -- -- Implements Better conversion as defined in section 14.4.2.3 -- of ECMA-364 -- type family IsBetterConv (s::Type) (t1::Type) (t2::Type) :: Bool where IsBetterConv s t1 t2 = BestType s t1 t2 == 'Just t1 type family BestType (s::Type) (t1::Type) (t2::Type) :: Maybe Type where BestType s t t = 'Nothing BestType t1 t1 t2 = 'Just t1 BestType t2 t1 t2 = 'Just t2 BestType s t1 t2 = BestType' (ImplicitConvExists t1 t2) t1 (ImplicitConvExists t2 t1) t2 type family BestType' (b1::Bool) (t1::Type) (b2::Bool) (t2::Type) :: Maybe Type where BestType' 'True t1 'False t2 = 'Just t1 BestType' 'False t1 'True t2 = 'Just t2 BestType' _ t1 _ t2 = (BestType'' t1 t2) <|> (BestType'' t2 t1) type family BestType'' (t1::Type) (t2::Type) :: Maybe Type where BestType'' (T "System.SByte" '[]) t2 = If (t2 `Elem` UNumAtLeastSByte) ('Just (T "System.SByte" '[])) 'Nothing BestType'' (T "System.Int16" '[]) t2 = If (t2 `Elem` UNumAtLeastInt16) ('Just (T "System.Int16" '[])) 'Nothing BestType'' (T "System.Int32" '[]) t2 = If (t2 `Elem` UNumAtLeastInt32) ('Just (T "System.Int32" '[])) 'Nothing BestType'' (T "System.Int64" '[]) t2 = If (t2 `Elem` UNumAtLeastInt64) ('Just (T "System.Int64" '[])) 'Nothing BestType'' t1 t2 = 'Nothing type family (a::k) <|> (b::k) :: k type family MaybeAlt (a::Maybe k) (b::Maybe k) :: Maybe k where MaybeAlt 'Nothing x = x MaybeAlt x 'Nothing = x type instance a <|> b = MaybeAlt a b type UNumAtLeastSByte = (T "System.Byte" '[]) ': UNumAtLeastInt32 type UNumAtLeastInt16 = (T "System.UInt16" '[]) ': UNumAtLeastInt32 type UNumAtLeastInt32 = (T "System.UInt32" '[]) ': UNumAtLeastInt64 type UNumAtLeastInt64 = '[ T "System.UInt64" '[] ]