{- CAO Compiler
Copyright (C) 2014 Cryptography and Information Security Group, HASLab - INESC TEC and Universidade do Minho
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . -}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-
Module : $Header$
Description : Unification of type when checking expressions.
Copyright : (C) 2014 Cryptography and Information Security Group, HASLab - INESC TEC and Universidade do Minho
License : GPL
Maintainer : Paulo Silva
Stability : experimental
Portability : non-portable
-}
module Language.CAO.Typechecker.Unification ( solve ) where
import Data.List (partition)
import Language.CAO.Common.Error
import Language.CAO.Common.Polynomial
import Language.CAO.Common.Var hiding (mrange)
import Language.CAO.Index
import Language.CAO.Type
import Language.CAO.Type.Utils
import Language.CAO.Typechecker.Constraint
import Language.CAO.Index.Eval
{-
Invariants:
* Coercions are directed, i.e., the left type coerces to the right type. The left
type is the actual type while the right type is the expected type.
* Unification is not directed, i.e., left and right types are interchangeable.
* Unification always takes a type variable which will take the type resulting of
the unification.
* Casts are directed. The left type is the source type and the right type is the
target type.
* The target type of a cast is always determined, i.e., it is not a type variable.
* After a cast of a type variable, this cannot occur again.
* Leafs (variables and constants) types cannot be unbounded type variables.
They are either base types or integer type variables.
* The list of constraints is collected in a post-order traversal of the expression.
This means that leafs in the expression are processed
before the operators. This as a number of implications:
- A given type variable only appears in a constraint *after* appearing as a result
of an unification. This means that unification is a kind of type variable
introduction.
- Since each unification resolves to a type which is not an unbounded variable,
all the subsequent occurences get replaced. This means that, when processing
constraints, unbounded variables can only occur as the result of an unification.
- It is possible that integer type variables are not instantiated. In this case,
the integer type is assumed.
-}
-- TODO: Missing tuple case
solve :: [Constraint] -> Either (ErrorCode Var) ([Substitution], [ICond Var])
solve [] = return ([], [])
solve (Equal t1 t2 : s) = solvePat (equals t1 t2) s
solve (Coerces t1 t2 : s) = solvePat (coerces t1 t2) s
solve (Unifies tv t1 t2 : s) = solvePat (unifies tv t1 t2) s
solve (UnifiesC tv t1 t2 : s) = solvePat (unifiesC tv t1 t2) s
solve (Casts t1 t2 : s) = solvePat (casts t1 t2) s
solve (ToAlgebraic t1 t2 : s) = solvePat (toAlgebraic t1 t2) s
solve (Mult tv t1 t2 : s) = solvePat (mult tv t1 t2) s
solve (Pow t1 t2 : s) = solvePat (power t1 t2) s
solve (Conc tv t1 t2 : s) = solvePat (conc tv t1 t2) s
solve (UnifiesL tv tlst : s) = solvePat (unifiesL tv tlst) s
solve (MAccess t1 t2 mi : s) = solvePat (maccess t1 t2 mi) s
solve (MRange t1 t2 i1 i2 i3 i4 : s) = solvePat (mrange t1 t2 i1 i2 i3 i4) s
solve (MRow t1 t2 i1 i2 mi : s) = solvePat (mrow t1 t2 i1 i2 mi) s
solve (MCol t1 t2 i1 i2 mi : s) = solvePat (mcol t1 t2 i1 i2 mi) s
solve (VBAccess t1 t2 mi : s) = solvePat (vbaccess t1 t2 mi) s
solve (VBRange t1 t2 i1 i2 : s) = solvePat (vbrange t1 t2 i1 i2) s
solvePat
:: Either (ErrorCode Var) ([Substitution], [ICond Var])
-> [Constraint]
-> Either (ErrorCode Var) ([Substitution], [ICond Var])
solvePat f s = do
(sbs, c) <- f
(s', c') <- solve (substitution sbs s)
let sbs' = substSqrL s' sbs
return (sbs' ++ s', c ++ c')
skip :: Either (ErrorCode Var) ([Substitution], [ICond Var])
skip = return ([], [])
self :: Type Var -> Substitution
self t@(TyVar n) = Subst n t
self t@(IntVar n) = Subst n t
self t@(ModVar n) = Subst n t
self _ = error "self substitution: not expected"
equals :: Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
equals Bool Bool = skip
equals RInt RInt = skip
equals Int Int = skip
equals (IntVar n1) t2@(IntVar n2)
| n1 == n2 = skip
| otherwise = return ([Subst n1 t2, self t2], [])
equals t1@(IntVar n1) t2
| isInt t2 = return ([Subst n1 t2], [])
| otherwise = Left (TypeMismatchException t1 t2 MatchException)
equals t1 t2@(IntVar n2)
| isInt t1 = return ([Subst n2 t1], [])
| otherwise = Left (TypeMismatchException t1 t2 MatchException)
equals (Bits s1 n1) (Bits s2 n2) | s1 == s2 = return ([], [n1 .==. n2])
equals (ModVar m1) t2@(ModVar m2)
| m1 == m2 = skip
| otherwise = return ([Subst m1 t2, self t2], [])
-- TODO: missing cases for ModVar's
equals (Mod Nothing Nothing (Pol [Mon (CoefI n1) EZero]))
(Mod Nothing Nothing (Pol [Mon (CoefI n2) EZero])) =
return ([], [n1 .==. n2])
equals (Mod (Just t1) v1 p1) (Mod (Just t2) v2 p2) | v1 == v2 = do
(s', c') <- equals t1 t2
c'' <- eqPol p1 p2
return (s', c' ++ c'')
equals (Vector i1 t1) (Vector i2 t2) = do
(s', c') <- equals t1 t2
return (s', i1 .==. i2 : c')
equals (Matrix i1 j1 t1) (Matrix i2 j2 t2) = do
(s', c') <- equals t1 t2
let c = [i1 .==. i2, j1 .==. j2]
return (s', c ++ c')
equals (Struct s1 _) (Struct s2 _) | s1 == s2 = skip
equals t1 t2 = Left (TypeMismatchException t1 t2 MatchException)
coerces :: Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
coerces Bool Bool = skip
coerces RInt RInt = skip
coerces Int Int = skip
-- When two integer type variables are compared:
-- - if they are equal, they can be removed since they add no information
-- - if they are different, one replaces all occurrences of the other
coerces (IntVar n1) t2@(IntVar n2)
| n1 == n2 = skip
| otherwise = return ([Subst n1 t2, self t2], [])
-- When a integer type variable is being coerced to another type, the target type
-- can only be an integer (rint or int) type, since integers cannot be coerced to any
-- other type.
-- - The integer type variable is replaced by the target type in all its occurrences.
-- - Otherwise, the coercion is not possible
coerces t1@(IntVar n1) t2
| isInt t2 = return ([Subst n1 t2], [])
| otherwise = Left (TypeMismatchException t1 t2 MatchException)
-- When a type is being coerced to an integer type variable, the source type can be
-- either a bit string or an integer (rint or int) by the possible coercion rules.
-- - if it is an integer type, this type replaces all occurrences of the variable
-- - if it is a bit string, this implies that the variable type is int, since coercions
-- to rint are not allowed.
coerces t1 (IntVar n2)
| isInt t1 = return ([Subst n2 t1], [])
| isBits t1 = return ([Subst n2 Int], [])
-- Index
coerces t1 (Index _ _ t2) = coerces t1 t2
-- Bits to Integers
coerces (Bits _ _) Int = skip
-- Bits
coerces (Bits s1 n1) (Bits s2 n2) | s1 == s2 = return ([], [n1 .==. n2])
-- Mod's
-- What may happen if the base of a Mod is an integer? Should that be possible?
coerces (ModVar m1) t2@(ModVar m2)
| m1 == m2 = skip
| otherwise = return ([Subst m1 t2, self t2], [])
coerces (ModVar m1) m2@(Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) =
return ([Subst m1 m2], [])
coerces (ModVar m1) (Mod (Just t2) _ _) = coerces (ModVar m1) t2
-- TODO: missing cases for ModVar's
--coerces (Mod Nothing Nothing (Pol [])) (Mod {}) = skip
coerces (Mod Nothing Nothing (Pol [Mon (CoefI n1) EZero]))
(Mod Nothing Nothing (Pol [Mon (CoefI n2) EZero])) =
return ([], [n1 .==. n2])
coerces (Mod (Just t1) v1 p1) (Mod (Just t2) v2 p2) | v1 == v2 = do
(s', c') <- coerces t1 t2
c'' <- eqPol p1 p2
return (s', c' ++ c'')
coerces t1 (Mod (Just b) _ _) = coerces t1 b
-- Vectors
coerces (Vector i1 t1) (Vector i2 t2) = do
(s', c') <- coerces t1 t2
return (s', i1 .==. i2 : c')
-- Matrices
coerces (Matrix i1 j1 t1) (Matrix i2 j2 t2) = do
(s', c') <- coerces t1 t2
let c = [i1 .==. i2, j1 .==. j2]
return (s', c ++ c')
coerces (Struct s1 _) (Struct s2 _) | s1 == s2 = skip
coerces t1 t2 = Left (TypeMismatchException t1 t2 MatchException)
eqPol :: Pol Var -> Pol Var -> Either (ErrorCode Var) [ICond Var]
eqPol (Pol p1) (Pol p2) = eqPolLst p1 p2
where
eqPolLst [] [] = return []
eqPolLst (m1 : mlst1) (m2 : mlst2) = do
c1 <- eqMon m1 m2
c2 <- eqPolLst mlst1 mlst2
return (c1 ++ c2)
eqPolLst _ _ = Left $ UnknownErr "eqPol: <>: eqPolLst"
eqMon (Mon c1 b1) (Mon c2 b2) = do
c1' <- eqCoef c1 c2
_ <- eqBase b1 b2
return c1'
eqCoef (CoefI i1) (CoefI i2) = return [i1 .==. i2]
eqCoef (CoefP pl1) (CoefP pl2) = eqPol pl1 pl2
eqCoef _ _ = Left $ UnknownErr "eqPol: <>: eqCoef"
eqBase EZero EZero = return []
eqBase (MExpI v1 e1) (MExpI v2 e2) | v1 == v2 && e1 == e2 = return []
eqBase _ _ = Left $ UnknownErr "eqPol: <>: eqBase"
unifies :: Type Var -> Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
-- Operations on bits imply a coercion to Int. This rule must come
-- before the rest of unification, otherwise, equal bit string types
-- would unify to themselves.
unifies (TyVar tv) (Bits _ _) (Bits _ _) = return ([Subst tv Int], [])
unifies (TyVar tv) t1@(IntVar n1) t2@(IntVar n2)
| n1 == n2 = return ([Subst tv t2, self t1, self t2], [])
| otherwise = return ([Subst n1 t2, Subst tv t2, self t2], [])
-- Unification of an integer type variable with a integer type
-- returns this integer type.
-- Unification of an integer type variable with a bit string
-- returns an integer (the only possible unification)
unifies (TyVar tv) (IntVar n1) t2
| isInt t2 = return ([Subst n1 t2, Subst tv t2], [])
| isBits t2 = return ([Subst n1 Int, Subst tv Int], [])
-- Symmetric case of the above
unifies (TyVar tv) t1 (TyVar n2)
| isInt t1 = return ([Subst n2 t1, Subst tv t1], [])
| isBits t1 = return ([Subst n2 Int, Subst tv Int], [])
unifies (TyVar tv) t1@(ModVar m1) t2@(ModVar m2)
| m1 == m2 = return ([Subst tv t2, self t1, self t2], [])
| otherwise = return ([Subst m1 t2, Subst tv t2, self t2], [])
-- Mod variables
unifies (TyVar tv) (ModVar m1) m2@(Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) =
return ([Subst m1 m2, Subst tv m2], [])
unifies (TyVar tv) (ModVar m1) (Mod (Just t2) _ _) = unifies (TyVar tv) (ModVar m1) t2
unifies (TyVar tv) m1@(Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) (ModVar m2) =
return ([Subst m2 m1, Subst tv m1], [])
unifies (TyVar tv) (Mod (Just t1) _ _) (ModVar m2) = unifies (TyVar tv) (ModVar m2) t1
-- Unification cannot rely on just coercion for the case of vectors
-- and matrices, because of the unification must be propagated
-- through the structure.
-- Unification of Vectors
unifies (TyVar tv) (Vector i1 t1) (Vector i2 t2) = do
(sbs, c') <- unifies (TyVar tv) t1 t2
let tv' = subst' sbs (TyVar tv) -- This can be improved...
sbs' = Subst tv (Vector i1 tv') : remove tv sbs -- Arbitrary choice since i1 and i2 must be equal
return (sbs', i1 .==. i2 : c')
-- Unification of Matrices
unifies (TyVar tv) (Matrix i1 j1 t1) (Matrix i2 j2 t2) = do
(sbs, c') <- unifies (TyVar tv) t1 t2
let tv' = subst' sbs (TyVar tv) -- This can be improved...
sbs' = Subst tv (Matrix i1 j1 tv') : remove tv sbs -- Arbitrary choice since i1 and i2 must be equal
c = i1 .==. i2 : j1 .==. j2 : c'
return (sbs', c)
unifies (TyVar tv) s@(Struct s1 _) (Struct s2 _) | s1 == s2 =
return ([Subst tv s], [])
-- General unification case uses coercions
-- TODO: use try/catch??
unifies (TyVar tv) t1 t2 = case coerces t1 t2 of
Left _ -> case coerces t2 t1 of
Left _ -> Left (TypeMismatchException t1 t2 UnificationException)
Right (sbs, c) -> do
let sbs' = Subst tv (subst' sbs t1) : sbs
return (sbs', c)
Right (sbs, c) -> do
let sbs' = Subst tv (subst' sbs t2) : sbs
return (sbs', c)
unifies _ t1 t2 = Left (TypeMismatchException t1 t2 UnificationException)
--casts' t1 t2 | isModInt t1 = return $ isIntExt t2 || isModInt t2
casts :: Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
casts RInt Int = skip
casts Int RInt = skip
-- Any integer type variable is castable to an int or rint
-- So, we can assume that the source type is equal to the target type
casts (IntVar n) Int = return ([Subst n Int], [])
casts (IntVar n) RInt = return ([Subst n RInt], [])
-- rint's are not directly castable to bits to avoid errors.
-- This also means that an integer type variable is only castable
-- to bits if it is an int.
casts (IntVar n) (Bits _ _) = return ([Subst n Int], [])
casts Int (Bits _ _) = skip
casts (Bits {}) (Bits {}) = skip
casts (ModVar _) Int = skip
casts (ModVar _) (Bits _ _) = skip
casts (ModVar _) (Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) = skip
casts (ModVar _) (Mod (Just _) (Just _) (Pol _)) = skip
casts (Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) Int = skip
casts (Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) (Bits _ _) = skip -- Possible through int
casts (Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) (Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) = skip
casts (Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) (Mod (Just _) (Just _) (Pol _)) = skip
casts Int (Mod {}) = skip
-- This is only possible when the integer type variable is an Int
casts (IntVar n) (Mod {}) = return ([Subst n Int], [])
casts (Bits _ _) (Mod {}) = skip
{-
casts Int (Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) = skip
casts (Bits _ _) (Mod Nothing Nothing (Pol [Mon (CoefI _) EZero])) = skip -- Possible through int
casts Int (Mod (Just bt) (Just v) _) = skip
casts (Bits _ _) (Mod (Just bt) (Just v) _) = skip-}
casts (Vector i1 t1) (Mod (Just bt) (Just _) pol) = do
(sbs, c) <- casts t1 bt
return (sbs, i1 .==. IInt (degree pol) : c)
casts (Mod (Just bt) (Just _) pol) (Vector i2 t2) = do
(sbs, c) <- casts bt t2
return (sbs, i2 .==. IInt (degree pol) : c)
casts (Matrix i1 j1 t1) (Mod (Just bt) (Just _) pol) = do
(sbs, c) <- casts t1 bt
let deg = IInt $ degree pol
c' = IAnd [i1 .==. IInt 1, j1 .==. deg] .||. IAnd [j1 .==. IInt 1, i1 .==. deg]
return (sbs, c' : c)
casts (Mod (Just bt) (Just _) pol) (Matrix i2 j2 t2) = do
(sbs, c) <- casts bt t2
let deg = IInt $ degree pol
c' = IAnd [i2 .==. IInt 1, deg .==. j2] .||. IAnd [j2 .==. IInt 1, deg .==. i2]
return (sbs, c' : c)
casts (Matrix i1 j1 t1) (Vector i2 t2) = do
(sbs, c) <- casts t1 t2
let c' = IAnd [i1 .==. IInt 1, j1 .==. i2] .||. IAnd [j1 .==. IInt 1, i1 .==. i2]
return (sbs, c' : c)
casts (Vector i1 t1) (Matrix i2 j2 t2) = do
(sbs, c) <- casts t1 t2
let c' = IAnd [i2 .==. IInt 1, i1 .==. j2] .||. IAnd [j2 .==. IInt 1, i1 .==. i2]
return (sbs, c' : c)
casts (Vector i1 t1) (Vector i2 t2) = do
(sbs, c) <- casts t1 t2
return (sbs, i1 .==. i2 : c)
casts (Matrix i1 j1 t1) (Matrix i2 j2 t2) = do
(sbs, c) <- casts t1 t2
return (sbs, i1 .==. i2 : j1 .==. j2 : c)
casts (Tuple t1) (Tuple t2) = solve $ zipWith Casts t1 t2
casts t1 t2 = either (const (Left (TypeMismatchException t1 t2 CastException))) Right (coerces t1 t2)
toAlgebraic :: Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
toAlgebraic (TyVar tv) (Bits _ _) = return ([Subst tv Int], [])
toAlgebraic (TyVar tv) t = return ([Subst tv t], [])
toAlgebraic _ _ = Left (UnknownErr "toAlgebraic")
mult :: Type Var -> Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
mult (TyVar tv) (Matrix r1 c1 t1) (Matrix r2 c2 t2) = do
(sbs, c) <- mult (TyVar tv) t1 t2
let tv' = subst' sbs (TyVar tv)
sbs' = Subst tv (Matrix r1 c2 tv') : remove tv sbs
return (sbs', c ++ [c1 .==. r2])
mult tv@(TyVar _) t1 t2 = unifies tv t1 t2
mult _ t1 t2 = Left (TypeMismatchException t1 t2 UnificationException)
power :: Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
power (TyVar tv) (Matrix r1 c1 t) = do
(sbs, c) <- power (TyVar tv) t
let tv' = subst' sbs (TyVar tv)
sbs' = Subst tv (Matrix r1 c1 tv') : remove tv sbs
return (sbs', c ++ [r1 .==. c1])
power (TyVar tv) (Bits _ _) = do -- Coercible to Int
return ([Subst tv Int], [])
power (TyVar tv) t =
return ([Subst tv t], [])
power t1 t2 = Left (TypeMismatchException t1 t2 UnificationException)
-- This is a particular case for concatenation of vectores and equality. The unification of equal bit strings
-- should be a bit string. In all other cases, bit strings are taken as integers.
-- This may be a result of a poor design...
unifiesC :: Type Var -> Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
unifiesC (TyVar tv) (Bits s1 (IInt n1)) (Bits s2 (IInt n2)) | s1 == s2 && n1 == n2 =
return ([Subst tv (Bits s1 (IInt n1))], [])
-- TODO: Add the general case for testing bit string sizes with arbitrary case
unifiesC tv t1 t2 = unifies tv t1 t2
conc :: Type Var -> Type Var -> Type Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
conc (TyVar tv) (Bits s1 n1) (Bits s2 n2) | s1 == s2 =
return ([Subst tv (Bits s1 (evalExpr (ISum [n1, n2])))], [])
conc (TyVar tv) (Vector n1 t1) (Vector n2 t2) = do
(sbs, c) <- unifiesC (TyVar tv) t1 t2
let tv' = subst' sbs (TyVar tv)
sbs' = Subst tv (Vector (evalExpr (ISum [n1, n2])) tv') : remove tv sbs -- TODO: improve this pattern
return (sbs', c)
conc _ t1 t2 = Left (TypeMismatchException t1 t2 UnificationException)
isModVar :: Type Var -> Bool
isModVar m = case m of
ModVar _ -> True
_ -> False
unifiesL :: Type Var -> [Type Var] -> Either (ErrorCode Var) ([Substitution], [ICond Var])
unifiesL _ [] = error ".: not expected empty case"
-- There is nothing to unify
unifiesL (TyVar tv) [t] = return ([Subst tv t], [])
unifiesL (TyVar tv) tlst =
let (modvars, tvars) = partition isModVar tlst
in if null tvars
then return (sbsLst tv (tail modvars) (head modvars), [])
else do
(tu, c) <- aux (TyVar tv) tvars
let sbs = sbsLst tv modvars tu
return (sbs, c)
where
sbsLst t modvars tu = Subst t tu : zipWith (\ (ModVar v) -> Subst v) modvars (repeat tu)
aux _ [t] = return (t, [])
aux tv' (t:ts) = aux' tv' t ts []
aux _ _ = error "unifiesL.aux: Not expected case"
aux' _ tu [] cs = return (tu, cs)
aux' tv' tu (t:ts) cs = do
(sbs, c) <- unifies tv' t tu
let tu' = subst' sbs tv'
aux' tv' tu' ts (c ++ cs)
unifiesL _ _ = error ".: not expected case"
maccess :: Type Var -> Type Var -> Maybe (IExpr Var, IExpr Var) -> Either (ErrorCode Var) ([Substitution], [ICond Var])
maccess (TyVar tv) (Matrix u v t) mi = return ([Subst tv t], cAccessM u v mi)
maccess _ t2 _ = Left $ WrongTypeException t2 MatrixType
mrange :: Type Var -> Type Var -> IExpr Var -> IExpr Var -> IExpr Var -> IExpr Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
mrange (TyVar tv) (Matrix u v it) i1 i2 i3 i4 =
return ( [Subst tv (Matrix (cSize i1 i2) (cSize i3 i4) it)]
, cRange u i1 i2 ++ cRange v i3 i4)
mrange _ t2 _ _ _ _ = Left $ WrongTypeException t2 MatrixType
mrow :: Type Var -> Type Var -> IExpr Var -> IExpr Var -> Maybe (IExpr Var) -> Either (ErrorCode Var) ([Substitution], [ICond Var])
mrow (TyVar tv) (Matrix v u it) i1 i2 mi =
return ([Subst tv (Matrix (IInt 1) (cSize i1 i2) it)], cRange u i1 i2 ++ cAccess v mi)
mrow _ t2 _ _ _ = Left $ WrongTypeException t2 MatrixType
mcol :: Type Var -> Type Var -> IExpr Var -> IExpr Var -> Maybe (IExpr Var) -> Either (ErrorCode Var) ([Substitution], [ICond Var])
mcol (TyVar tv) (Matrix v u it) i1 i2 mi = do
return ([Subst tv (Matrix (cSize i1 i2) (IInt 1) it)], cRange v i1 i2 ++ cAccess u mi)
mcol _ t2 _ _ _ = Left $ WrongTypeException t2 MatrixType
vbaccess :: Type Var -> Type Var -> Maybe (IExpr Var) -> Either (ErrorCode Var) ([Substitution], [ICond Var])
vbaccess (TyVar tv) (Bits s k) mi = return ([Subst tv (Bits s (IInt 1))], cAccess k mi)
vbaccess (TyVar tv) (Vector k t) mi = return ([Subst tv t], cAccess k mi)
vbaccess _ t2 _ = Left $ WrongTypeException t2 BitsOrVectorType
vbrange :: Type Var -> Type Var -> IExpr Var -> IExpr Var -> Either (ErrorCode Var) ([Substitution], [ICond Var])
vbrange (TyVar tv) (Bits s k) i1 i2 =
return ([Subst tv (Bits s (cSize i1 i2))], cRange k i1 i2)
vbrange (TyVar tv) (Vector k t) i1 i2 =
return ([Subst tv (Vector (cSize i1 i2) t)], cRange k i1 i2)
vbrange _ t2 _ _ = Left $ WrongTypeException t2 BitsOrVectorType
-----------------------------------
-- TODO: This code is shared with Check.hs
cRange :: IExpr Var -> IExpr Var -> IExpr Var -> [ICond Var]
cRange s i j = [j .<. s, i .<=. j, IInt 0 .<=. i]
cSize :: IExpr Var -> IExpr Var -> IExpr Var
cSize i j = evalExpr $ ISum [ j, ISym i, IInt 1 ]
cAccessM :: IExpr Var -> IExpr Var -> Maybe (IExpr Var, IExpr Var) -> [ICond Var]
cAccessM _ _ Nothing = []
cAccessM u v (Just (i, j)) = [IInt 0 .<=. i, i .<. u, IInt 0 .<=. j, j .<. v]
cAccess :: IExpr Var -> Maybe (IExpr Var) -> [ICond Var]
cAccess _ Nothing = []
cAccess k (Just i) = [IInt 0 .<=. i, i .<. k]
----------------------------