{-# LANGUAGE PatternGuards, OverloadedStrings #-}
module Cryptol.TypeCheck.Solver.Class
( solveZeroInst
, solveLogicInst
, solveRingInst
, solveFieldInst
, solveIntegralInst
, solveRoundInst
, solveEqInst
, solveCmpInst
, solveSignedCmpInst
, solveLiteralInst
, solveFLiteralInst
, solveValidFloat
) where
import qualified LibBF as FP
import Cryptol.TypeCheck.Type
import Cryptol.TypeCheck.SimpType (tAdd,tWidth)
import Cryptol.TypeCheck.Solver.Types
import Cryptol.TypeCheck.PP
import Cryptol.Utils.RecordMap
solveValidFloat :: Type -> Type -> Solved
solveValidFloat e p
| Just _ <- knownSupportedFloat e p = SolvedIf []
| otherwise = Unsolved
knownSupportedFloat :: Type -> Type -> Maybe FP.BFOpts
knownSupportedFloat et pt
| Just e <- tIsNum et, Just p <- tIsNum pt
, minExp <= e && e <= maxExp && minPrec <= p && p <= maxPrec =
Just (FP.expBits (fromInteger e) <> FP.precBits (fromInteger p)
<> FP.allowSubnormal)
| otherwise = Nothing
where
minExp = max 2 (toInteger FP.expBitsMin)
maxExp = toInteger FP.expBitsMax
minPrec = max 2 (toInteger FP.precBitsMin)
maxPrec = toInteger FP.precBitsMax
solveZeroInst :: Type -> Solved
solveZeroInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCBit) [] -> SolvedIf []
TCon (TC TCInteger) [] -> SolvedIf []
TCon (TC TCIntMod) [n] -> SolvedIf [ pFin n, n >== tOne ]
TCon (TC TCRational) [] -> SolvedIf []
TCon (TC TCFloat) [e,p] -> SolvedIf [ pValidFloat e p ]
TCon (TC TCSeq) [_, a] -> SolvedIf [ pZero a ]
TCon (TC TCFun) [_, b] -> SolvedIf [ pZero b ]
TCon (TC (TCTuple _)) es -> SolvedIf [ pZero e | e <- es ]
TRec fs -> SolvedIf [ pZero ety | ety <- recordElements fs ]
_ -> Unsolved
solveLogicInst :: Type -> Solved
solveLogicInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCBit) [] -> SolvedIf []
TCon (TC TCInteger) [] ->
Unsolvable $
TCErrorMessage "Type 'Integer' does not support logical operations."
TCon (TC TCIntMod) [_] ->
Unsolvable $
TCErrorMessage "Type 'Z' does not support logical operations."
TCon (TC TCRational) [] ->
Unsolvable $
TCErrorMessage "Type 'Rational' does not support logical operations."
TCon (TC TCFloat) [_, _] ->
Unsolvable $
TCErrorMessage "Type 'Float' does not support logical operations."
TCon (TC TCSeq) [_, a] -> SolvedIf [ pLogic a ]
TCon (TC TCFun) [_, b] -> SolvedIf [ pLogic b ]
TCon (TC (TCTuple _)) es -> SolvedIf [ pLogic e | e <- es ]
TRec fs -> SolvedIf [ pLogic ety | ety <- recordElements fs ]
_ -> Unsolved
solveRingInst :: Type -> Solved
solveRingInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCSeq) [n, e] -> solveRingSeq n e
TCon (TC TCFun) [_,b] -> SolvedIf [ pRing b ]
TCon (TC (TCTuple _)) es -> SolvedIf [ pRing e | e <- es ]
TCon (TC TCBit) [] ->
Unsolvable $ TCErrorMessage "Type 'Bit' does not support ring operations."
TCon (TC TCInteger) [] -> SolvedIf []
TCon (TC TCIntMod) [n] -> SolvedIf [ pFin n, n >== tOne ]
TCon (TC TCRational) [] -> SolvedIf []
TCon (TC TCFloat) [e,p] -> SolvedIf [ pValidFloat e p ]
TRec fs -> SolvedIf [ pRing ety | ety <- recordElements fs ]
_ -> Unsolved
solveRingSeq :: Type -> Type -> Solved
solveRingSeq n ty = case tNoUser ty of
TCon (TC TCBit) [] -> SolvedIf [ pFin n ]
TVar {} -> case tNoUser n of
TCon (TC TCInf) [] -> SolvedIf [ pRing ty ]
_ -> Unsolved
_ -> SolvedIf [ pRing ty ]
solveIntegralInst :: Type -> Solved
solveIntegralInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCBit) [] ->
Unsolvable $ TCErrorMessage "Type 'Bit' is not an integral type."
TCon (TC TCInteger) [] -> SolvedIf []
TCon (TC TCSeq) [n, elTy] ->
case tNoUser elTy of
TCon (TC TCBit) [] -> SolvedIf [ pFin n ]
TVar _ -> Unsolved
_ -> Unsolvable $ TCErrorMessage $ show
$ "Type" <+> quotes (pp ty) <+> "is not an integral type."
TVar _ -> Unsolved
_ -> Unsolvable $ TCErrorMessage $ show
$ "Type" <+> quotes (pp ty) <+> "is not an integral type."
solveFieldInst :: Type -> Solved
solveFieldInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCBit) [] ->
Unsolvable $
TCErrorMessage "Type 'Bit' does not support field operations."
TCon (TC TCInteger) [] ->
Unsolvable $
TCErrorMessage "Type 'Integer' does not support field operations."
TCon (TC TCRational) [] -> SolvedIf []
TCon (TC TCFloat) [e,p] -> SolvedIf [ pValidFloat e p ]
TCon (TC TCIntMod) [_] ->
Unsolvable $
TCErrorMessage "Type 'Z' does not support field operations."
TCon (TC TCSeq) [_, _] ->
Unsolvable $
TCErrorMessage "Sequence types do not support field operations."
TCon (TC TCFun) [_, _] ->
Unsolvable $
TCErrorMessage "Function types do not support field operations."
TCon (TC (TCTuple _)) _ ->
Unsolvable $
TCErrorMessage "Tuple types do not support field operations."
TRec _ ->
Unsolvable $
TCErrorMessage "Record types do not support field operations."
_ -> Unsolved
solveRoundInst :: Type -> Solved
solveRoundInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCBit) [] ->
Unsolvable $
TCErrorMessage "Type 'Bit' does not support rounding operations."
TCon (TC TCInteger) [] ->
Unsolvable $
TCErrorMessage "Type 'Integer' does not support rounding operations."
TCon (TC TCIntMod) [_] ->
Unsolvable $
TCErrorMessage "Type 'Z' does not support rounding operations."
TCon (TC TCRational) [] -> SolvedIf []
TCon (TC TCFloat) [e,p] -> SolvedIf [ pValidFloat e p ]
TCon (TC TCSeq) [_, _] ->
Unsolvable $
TCErrorMessage "Sequence types do not support rounding operations."
TCon (TC TCFun) [_, _] ->
Unsolvable $
TCErrorMessage "Function types do not support rounding operations."
TCon (TC (TCTuple _)) _ ->
Unsolvable $
TCErrorMessage "Tuple types do not support rounding operations."
TRec _ ->
Unsolvable $
TCErrorMessage "Record types do not support rounding operations."
_ -> Unsolved
solveEqInst :: Type -> Solved
solveEqInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCBit) [] -> SolvedIf []
TCon (TC TCInteger) [] -> SolvedIf []
TCon (TC TCRational) [] -> SolvedIf []
TCon (TC TCFloat) [e,p] -> SolvedIf [ pValidFloat e p ]
TCon (TC TCIntMod) [n] -> SolvedIf [ pFin n, n >== tOne ]
TCon (TC TCSeq) [n,a] -> SolvedIf [ pFin n, pEq a ]
TCon (TC (TCTuple _)) es -> SolvedIf (map pEq es)
TCon (TC TCFun) [_,_] ->
Unsolvable $ TCErrorMessage "Function types do not support comparisons."
TRec fs -> SolvedIf [ pEq e | e <- recordElements fs ]
_ -> Unsolved
solveCmpInst :: Type -> Solved
solveCmpInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCBit) [] -> SolvedIf []
TCon (TC TCInteger) [] -> SolvedIf []
TCon (TC TCRational) [] -> SolvedIf []
TCon (TC TCIntMod) [_] ->
Unsolvable $ TCErrorMessage "Type 'Z' does not support order comparisons."
TCon (TC TCFloat) [e,p] -> SolvedIf [ pValidFloat e p ]
TCon (TC TCSeq) [n,a] -> SolvedIf [ pFin n, pCmp a ]
TCon (TC (TCTuple _)) es -> SolvedIf (map pCmp es)
TCon (TC TCFun) [_,_] ->
Unsolvable $ TCErrorMessage "Function types do not support order comparisons."
TRec fs -> SolvedIf [ pCmp e | e <- recordElements fs ]
_ -> Unsolved
solveSignedCmpSeq :: Type -> Type -> Solved
solveSignedCmpSeq n ty = case tNoUser ty of
TCon (TC TCBit) [] -> SolvedIf [ pFin n, n >== tNum (1 :: Integer) ]
TVar {} -> Unsolved
_ -> SolvedIf [ pFin n, pSignedCmp ty ]
solveSignedCmpInst :: Type -> Solved
solveSignedCmpInst ty = case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCBit) [] ->
Unsolvable $
TCErrorMessage "Type 'Bit' does not support signed comparisons."
TCon (TC TCInteger) [] ->
Unsolvable $
TCErrorMessage "Type 'Integer' does not support signed comparisons."
TCon (TC TCIntMod) [_] ->
Unsolvable $
TCErrorMessage "Type 'Z' does not support signed comparisons."
TCon (TC TCRational) [] ->
Unsolvable $
TCErrorMessage "Type 'Rational' does not support signed comparisons."
TCon (TC TCFloat) [_, _] ->
Unsolvable $
TCErrorMessage "Type 'Float' does not support signed comparisons."
TCon (TC TCSeq) [n,a] -> solveSignedCmpSeq n a
TCon (TC (TCTuple _)) es -> SolvedIf (map pSignedCmp es)
TCon (TC TCFun) [_,_] ->
Unsolvable $
TCErrorMessage "Function types do not support signed comparisons."
TRec fs -> SolvedIf [ pSignedCmp e | e <- recordElements fs ]
_ -> Unsolved
solveFLiteralInst :: Type -> Type -> Type -> Type -> Solved
solveFLiteralInst numT denT rndT ty
| TCon (TError _ e) _ <- tNoUser numT = Unsolvable e
| TCon (TError _ e) _ <- tNoUser denT = Unsolvable e
| tIsInf numT || tIsInf denT || tIsInf rndT =
Unsolvable $ TCErrorMessage $ "Fractions may not use `inf`"
| Just 0 <- tIsNum denT =
Unsolvable $ TCErrorMessage
$ "Fractions may not have 0 as the denominator."
| otherwise =
case tNoUser ty of
TVar {} -> Unsolved
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCRational) [] ->
SolvedIf [ pFin numT, pFin denT, denT >== tOne ]
TCon (TC TCFloat) [e,p]
| Just 0 <- tIsNum rndT ->
SolvedIf [ pValidFloat e p
, pFin numT, pFin denT, denT >== tOne ]
| Just _ <- tIsNum rndT
, Just opts <- knownSupportedFloat e p
, Just n <- tIsNum numT
, Just d <- tIsNum denT
-> case FP.bfDiv opts (FP.bfFromInteger n) (FP.bfFromInteger d) of
(_, FP.Ok) -> SolvedIf []
_ -> Unsolvable $ TCErrorMessage
$ show n ++ "/" ++ show d ++ " cannot be " ++
"represented in " ++ show (pp ty)
| otherwise -> Unsolved
_ -> Unsolvable $ TCErrorMessage $ show
$ "Type" <+> quotes (pp ty) <+> "does not support fractional literals."
solveLiteralInst :: Type -> Type -> Solved
solveLiteralInst val ty
| TCon (TError _ e) _ <- tNoUser val = Unsolvable e
| otherwise =
case tNoUser ty of
TCon (TError _ e) _ -> Unsolvable e
TCon (TC TCInteger) [] -> SolvedIf [ pFin val ]
TCon (TC TCRational) [] -> SolvedIf [ pFin val ]
TCon (TC TCFloat) [e,p]
| Just n <- tIsNum val
, Just opts <- knownSupportedFloat e p ->
let bf = FP.bfFromInteger n
in case FP.bfRoundFloat opts bf of
(bf1,FP.Ok) | bf == bf1 -> SolvedIf []
_ -> Unsolvable $ TCErrorMessage
$ show n ++ " cannot be " ++
"represented in " ++ show (pp ty)
| otherwise -> Unsolved
TCon (TC TCIntMod) [modulus] ->
SolvedIf [ pFin val, pFin modulus, modulus >== tAdd val tOne ]
TCon (TC TCSeq) [bits, elTy]
| TCon (TC TCBit) [] <- ety ->
SolvedIf [ pFin val, pFin bits, bits >== tWidth val ]
| TVar _ <- ety -> Unsolved
where ety = tNoUser elTy
TVar _ -> Unsolved
_ -> Unsolvable $ TCErrorMessage $ show
$ "Type" <+> quotes (pp ty) <+> "does not support integer literals."