diff --git a/frontends/RainTypes.hs b/frontends/RainTypes.hs index daf8060..29c0b4b 100644 --- a/frontends/RainTypes.hs +++ b/frontends/RainTypes.hs @@ -16,7 +16,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . -} -module RainTypes (checkExpressionTypes,constantFoldPass,performTypeUnification,recordInfNameTypes) where +module RainTypes (constantFoldPass,performTypeUnification,recordInfNameTypes) where import Control.Monad.State import Data.Generics @@ -96,7 +96,9 @@ performTypeUnification x <.< markParamPass <.< markAssignmentTypes <.< markCommTypes - $ x --TODO markup everything else + -- TODO mark up types in replicators + <.< markExpressionTypes + $ x -- Then, we do the unification: prs <- get >>* csUnifyPairs res <- liftIO $ mapM (uncurry unifyType) prs @@ -170,117 +172,14 @@ markParamPass = checkDepthM2 matchParamPassProc matchParamPassFunc matchParamPassFunc _ = return () -- | Checks the types in expressions -checkExpressionTypes :: Data t => t -> PassM t -checkExpressionTypes = applyDepthM checkExpression +markExpressionTypes :: Data t => t -> PassM t +markExpressionTypes = checkDepthM checkExpression where - -- | Checks the types of an expression where at least one type involved - -- is Time. - checkTimeExpression :: Meta -> A.DyadicOp -> (A.Type, A.Expression) -> - (A.Type, A.Expression) -> PassM A.Expression - checkTimeExpression m op (tlhs, lhs) (trhs, rhs) - = case (validOpWithTime op tlhs trhs) of - Nothing -> diePC m $ formatCode - "Operator: \"%\" is not valid on types: \"%\" and \"%\"" op tlhs trhs - Just (destLHS, destRHS) -> - if (isImplicitConversionRain tlhs destLHS) - && (isImplicitConversionRain trhs destRHS) - then return $ A.Dyadic m op (convert destLHS tlhs lhs) - (convert destRHS trhs rhs) - else diePC m $ formatCode - "Operator: \"%\" is not valid on types: \"%\" and \"%\" (implicit conversions not possible)" - op tlhs trhs - - checkExpression :: A.Expression -> PassM A.Expression - checkExpression e@(A.Dyadic m op lhs rhs) - = do tlhs <- astTypeOf lhs - trhs <- astTypeOf rhs - if (tlhs == A.Time || trhs == A.Time) - -- Expressions with times can have asymmetric types, - -- so we handle them specially: - then checkTimeExpression m op (tlhs, lhs) (trhs, rhs) - else - if (tlhs == trhs) - then - -- Types identical. At this point we consider whether the - -- user is adding two lists (in which case, correct the - -- operator), otherwise we just need to check the operator - -- is valid on the types (to avoid two channels of the same - -- type being added, for example) - case (tlhs, op) of - (A.List _, A.Plus) -> return $ A.Dyadic m A.Concat lhs rhs - _ -> if validOpSameType op tlhs - then return e - else diePC m $ formatCode - "Operator: \"%\" is not valid on type: \"%\"" - op tlhs - -- Types differ. If they are integers, we can look for - -- a common (more general) type for both of them to be cast - -- up into in order to perform the operation. - else if (isIntegerType tlhs && isIntegerType trhs) - then case (leastGeneralSharedTypeRain [tlhs,trhs]) of - Nothing -> diePC m $ formatCode "Cannot find a suitable type to convert expression to, types are: % and %" tlhs trhs - Just t -> if validOpSameType op t then return $ A.Dyadic m op (convert t tlhs lhs) (convert t trhs rhs) else diePC m $ - formatCode "Operator: \"%\" is not valid on type: \"%\"" op tlhs - else --The operands are not equal, and are not integers, and neither of them is a time type. Therefore this must be an error: - diePC m $ formatCode "Mis-matched types; no operator applies to types: % and %" tlhs trhs - checkExpression e@(A.Monadic m op rhs) - = do trhs <- astTypeOf rhs - if (op == A.MonadicMinus) - then case trhs of - A.Byte -> return $ A.Monadic m op $ convert A.Int16 trhs rhs - A.UInt16 -> return $ A.Monadic m op $ convert A.Int32 trhs rhs - A.UInt32 -> return $ A.Monadic m op $ convert A.Int64 trhs rhs - A.UInt64 -> diePC m $ formatCode "Cannot apply unary minus to type: % because there is no type large enough to safely contain the result" trhs - _ -> if (isIntegerType trhs) then return e else diePC m $ formatCode "Trying to apply unary minus to non-integer type: %" trhs - else if (op == A.MonadicNot) - then - case trhs of - A.Bool -> return e - _ -> diePC m $ formatCode "Cannot apply unary not to non-boolean type: %" trhs - else dieP m $ "Invalid Rain operator: \"" ++ show op ++ "\"" - checkExpression e@(A.Conversion m cm dest rhs) - = do src <- astTypeOf rhs - if (src == dest) - then return e - else if isImplicitConversionRain src dest - then return e - else diePC m $ formatCode "Invalid cast from: % to: %" - src dest - checkExpression e = return e - - convert :: A.Type -> A.Type -> A.Expression -> A.Expression - convert dest src e = if (dest == src) - then e - else A.Conversion (findMeta e) A.DefaultConversion dest e - - validOpSameType :: A.DyadicOp -> A.Type -> Bool - validOpSameType A.Plus t = isIntegerType t - validOpSameType A.Minus t = isIntegerType t - validOpSameType A.Times t = isIntegerType t && t /= A.Time - validOpSameType A.Div t = isIntegerType t && t /= A.Time - validOpSameType A.Rem t = isIntegerType t && t /= A.Time - validOpSameType A.Eq _ = True - validOpSameType A.NotEq _ = True - validOpSameType A.Less t = haveOrder t - validOpSameType A.LessEq t = haveOrder t - validOpSameType A.More t = haveOrder t - validOpSameType A.MoreEq t = haveOrder t - validOpSameType A.And A.Bool = True - validOpSameType A.Or A.Bool = True - validOpSameType _ _ = False - - -- | Takes an operator, the types of LHS and RHS, and returns Nothing if no cast will fix it, - -- or Just (needTypeLHS,needTypeRHS) for what types will be okay - validOpWithTime :: A.DyadicOp -> A.Type -> A.Type -> Maybe (A.Type,A.Type) - validOpWithTime A.Times A.Time _ = Just (A.Time, A.Int64) - validOpWithTime A.Times _ A.Time = Just (A.Int64, A.Time) - validOpWithTime A.Div A.Time _ = Just (A.Time, A.Int64) - --Any other operators involving Time are symmetric: - validOpWithTime op tlhs trhs = if (tlhs == trhs && validOpSameType op tlhs) then Just (tlhs,trhs) else Nothing - - - haveOrder :: A.Type -> Bool - haveOrder t = (isIntegerType t) || (t == A.Time) + -- TODO also check in a later pass that the op is valid + checkExpression :: Check A.Expression + checkExpression (A.Dyadic _ _ lhs rhs) + = markUnify lhs rhs + checkExpression _ = return () -- | Checks the types in assignments markAssignmentTypes :: Data t => t -> PassM t diff --git a/frontends/RainTypesTest.hs b/frontends/RainTypesTest.hs index a8740f3..ac18045 100644 --- a/frontends/RainTypesTest.hs +++ b/frontends/RainTypesTest.hs @@ -74,342 +74,6 @@ constantFoldTest = TestList lit :: Integer -> ExprHelper lit n = Lit $ int64Literal n - --- | An amazing amount of tests for testing the Rain type-checker for all the different forms of statement, --- such as assignment, expressions, communications, etc etc. ---TODO add typechecks for expressions involving channels -checkExpressionTest :: Test -checkExpressionTest = TestList - [ - --Already same types: - passSame 0 A.Int64 $ Dy (Var "x") A.Plus (Var "x") - ,passSame 1 A.Byte $ Dy (Var "xu8") A.Plus (Var "xu8") - - --Upcasting: - ,pass 100 A.Int64 (Dy (Var "x") A.Plus (Cast A.Int64 $ Var "xu8")) (Dy (Var "x") A.Plus (Var "xu8")) - ,pass 101 A.Int32 (Dy (Cast A.Int32 $ Var "x16") A.Plus (Cast A.Int32 $ Var "xu16")) (Dy (Var "x16") A.Plus (Var "xu16")) - - --Upcasting a cast: - ,pass 200 A.Int64 (Dy (Var "x") A.Plus (Cast A.Int64 $ Cast A.Int32 $ Var "xu8")) (Dy (Var "x") A.Plus (Cast A.Int32 $ Var "xu8")) - - --Impossible conversions: - ,fail 300 $ Dy (Var "x") A.Plus (Var "xu64") - - --Integer literals: - ,pass 400 A.Int16 (Dy (Var "x16") A.Plus (Cast A.Int16 $ int A.Int8 100)) (Dy (Var "x16") A.Plus (int A.Int8 100)) - ,pass 401 A.Int16 (Dy (Cast A.Int16 $ Var "x8") A.Plus (int A.Int16 200)) (Dy (Var "x8") A.Plus (int A.Int16 200)) - --This fails because you are trying to add a signed constant to an unsigned integer that cannot be expanded: - ,fail 402 $ Dy (Var "xu64") A.Plus (int A.Int64 0) - - --Monadic integer operations: - ,passSame 500 A.Int32 (Mon A.MonadicMinus (Var "x32")) - ,pass 501 A.Int32 (Mon A.MonadicMinus (Cast A.Int32 $ Var "xu16")) (Mon A.MonadicMinus (Var "xu16")) - ,fail 502 $ Mon A.MonadicMinus (Var "xu64") - ,pass 503 A.Int64 (Dy (Var "x") A.Plus (Cast A.Int64 $ Mon A.MonadicMinus (Var "x32"))) (Dy (Var "x") A.Plus (Mon A.MonadicMinus (Var "x32"))) - - --Mis-matched types (integer/boolean): - ,fail 600 $ Dy (Var "b") A.Plus (Var "x") - ,fail 601 $ Mon A.MonadicMinus (Var "b") - ,fail 602 $ Dy (Var "x") A.Or (Var "x") - ,fail 603 $ Dy (Var "x") A.Eq (Var "b") - ,fail 604 $ Dy (Var "b") A.Plus (Var "b") - ,fail 605 $ Dy (Var "b") A.Less (Var "b") - - --Comparisons between different integer types: - ,pass 700 A.Bool (Dy (Var "x") A.Eq (Cast A.Int64 $ Var "xu8")) (Dy (Var "x") A.Eq (Var "xu8")) - ,pass 701 A.Bool (Dy (Cast A.Int32 $ Var "x16") A.Less (Cast A.Int32 $ Var "xu16")) (Dy (Var "x16") A.Less (Var "xu16")) - ,pass 702 A.Bool (Dy (Var "x") A.More (Cast A.Int64 $ Cast A.Int32 $ Var "xu8")) (Dy (Var "x") A.More (Cast A.Int32 $ Var "xu8")) - ,fail 703 $ Dy (Var "x") A.Less (Var "xu64") - ,pass 704 A.Bool (Dy (Var "x16") A.NotEq (Cast A.Int16 $ int A.Int8 100)) (Dy (Var "x16") A.NotEq (int A.Int8 100)) - ,pass 705 A.Bool (Dy (Cast A.Int16 $ Var "x8") A.MoreEq (int A.Int16 200)) (Dy (Var "x8") A.MoreEq (int A.Int16 200)) - - - --Booleans (easy!) - ,passSame 1000 A.Bool $ Mon A.MonadicNot (Var "b") - ,passSame 1001 A.Bool $ Dy (Var "b") A.Or (Var "b") - ,passSame 1002 A.Bool $ Dy (Var "b") A.And (Mon A.MonadicNot $ Var "b") - - --Comparison (same types): - ,passSame 1100 A.Bool $ Dy (Var "b") A.Eq (Var "b") - ,passSame 1101 A.Bool $ Dy (Var "x") A.Eq (Var "x") - ,passSame 1102 A.Bool $ Dy (Var "xu8") A.NotEq (Var "xu8") - ,passSame 1103 A.Bool $ Dy (Var "x") A.Less (Var "x") - ,passSame 1104 A.Bool $ Dy (Dy (Var "x") A.Eq (Var "x")) A.And (Dy (Var "xu8") A.NotEq (Var "xu8")) - - --Invalid casts: - ,fail 2000 $ Cast A.Bool (Var "x") - ,fail 2001 $ Cast A.Bool (int A.Int8 0) - ,fail 2002 $ Cast A.Int8 (Var "b") - ,fail 2003 $ Cast A.Int8 (Var "x") - ,fail 2004 $ Cast A.Int8 (Var "xu8") - ,fail 2005 $ Cast A.Byte (Var "x8") - ,fail 2006 $ Cast A.UInt64 (Var "x8") - - --Valid casts: - ,passSame 2100 A.Bool $ Cast A.Bool (Var "b") - ,passSame 2101 A.Int64 $ Cast A.Int64 (Var "x") - ,passSame 2102 A.Int64 $ Cast A.Int64 (Var "x8") - ,passSame 2103 A.Int64 $ Cast A.Int64 (Var "xu8") - ,passSame 2104 A.Int64 $ Cast A.Int64 $ Cast A.Int32 $ Cast A.UInt16 $ Var "xu8" - ,passSame 2105 A.UInt64 $ Cast A.UInt64 (Var "xu8") - - --Assignments: - ,passAssignSame 3000 "x" (Var "x") - ,passAssignSame 3001 "xu8" (Var "xu8") - ,passAssignSame 3002 "b" (Var "b") - ,passAssignSame 3003 "x" $ Dy (Var "x") A.Plus (Var "x") - ,passAssignSame 3004 "b" $ Dy (Var "x8") A.Eq (Var "x8") - ,passAssignSame 3005 "x" $ Mon A.MonadicMinus (Var "x") - ,passAssignSame 3006 "x8" $ int A.Int8 0 - ,passAssignSame 3007 "b" EHTrue - --- ,passAssign 3100 "x" (Cast A.Int64 $ Var "xu8") (Var "xu8") - ,failAssign 3101 "xu8" (Var "x") - ,failAssign 3102 "x" (Var "b") - ,failAssign 3103 "b" (Var "x") - ,failAssign 3104 "x8" (Var "xu8") - ,failAssign 3105 "xu8" (Var "x8") --- ,passAssign 3106 "x" (Cast A.Int64 $ int A.Int8 0) (int A.Int8 0) - - -- Assignment with constants: - ,failAssign 3200 "X" (Var "x") - ,failAssign 3201 "X" (Var "X") - ,failAssign 3202 "X" (Var "xu8") - - --Conditionals: - ,passWhileIfSame 4000 $ Var "b" - ,passWhileIfSame 4001 $ Mon A.MonadicNot $ Var "b" - ,passWhileIfSame 4002 $ Dy (Var "x") A.Eq (Var "x") - ,passWhileIfSame 4003 $ EHTrue - - ,failWhileIf 4100 $ Var "x" - ,failWhileIf 4101 $ Dy (Var "x") A.Plus (Var "x") - - --Communication: - ,testAllCheckCommTypes 5000 - - -- TODO check not being able to read into a constant variable - - --Time types: - ,fail 6000 $ Dy (Var "t") A.Plus (Var "x") - ,fail 6001 $ Dy (Var "x") A.Minus (Var "t") - ,passSame 6002 A.Time $ Dy (Var "t") A.Plus (Var "t") - ,passSame 6003 A.Time $ Dy (Var "t") A.Minus (Var "t") - - ,fail 6100 $ Dy (Var "t") A.Times (Var "t") - ,passSame 6101 A.Time $ Dy (Var "t") A.Times (Var "x") - ,passSame 6102 A.Time $ Dy (Var "x") A.Times (Var "t") - ,pass 6103 A.Time (Dy (Var "t") A.Times (Cast A.Int64 $ Var "xu32")) (Dy (Var "t") A.Times (Var "xu32")) - ,pass 6104 A.Time (Dy (Cast A.Int64 $ Var "xu32") A.Times (Var "t")) (Dy (Var "xu32") A.Times (Var "t")) - ,fail 6105 $ Dy (Var "t") A.Times (Var "xu64") - ,fail 6106 $ Dy (Var "xu64") A.Times (Var "t") - ,passSame 6107 A.Time $ Dy (Dy (Var "x") A.Times (Var "t")) A.Plus (Dy (Var "t") A.Times (Var "x")) - ,fail 6108 $ Dy (Dy (Var "x") A.Times (Var "t")) A.Times (Dy (Var "t") A.Times (Var "x")) - - ,fail 6200 $ Dy (Var "t") A.Div (Var "t") - ,fail 6201 $ Dy (Var "x") A.Div (Var "t") - ,passSame 6202 A.Time $ Dy (Var "t") A.Div (Var "x") - ,pass 6203 A.Time (Dy (Var "t") A.Div (Cast A.Int64 $ Var "xu32")) (Dy (Var "t") A.Div (Var "xu32")) - ,fail 6204 $ Dy (Var "t") A.Div (Var "xu64") - - ,fail 6300 $ Dy (Var "t") A.Rem (Var "t") - ,fail 6301 $ Dy (Var "x") A.Rem (Var "t") - ,fail 6302 $ Dy (Var "t") A.Rem (Var "x") - - ,fail 6400 $ Cast A.Time (Var "x") - ,fail 6401 $ Cast A.Int64 (Var "t") - - ,passSame 6500 A.Bool $ Dy (Var "t") A.Eq (Var "t") - ,passSame 6501 A.Bool $ Dy (Var "t") A.NotEq (Var "t") - ,passSame 6502 A.Bool $ Dy (Var "t") A.Less (Var "t") - ,passSame 6503 A.Bool $ Dy (Var "t") A.More (Var "t") - - --Now statements: - ,testPassUntouched 7000 performTypeUnification (getTime $ variable "t") - ,TestCase $ testPassShouldFail "checkExpressionTest 7001" - (performTypeUnification $ getTime $ variable "x") state - - --Wait statements: - ,testPassUntouched 7100 performTypeUnification (waitFor $ exprVariable "t") - ,TestCase $ testPassShouldFail "checkExpressionTest 7101" (performTypeUnification $ waitFor $ exprVariable "x") state - ,testPassUntouched 7102 performTypeUnification (waitFor $ buildExpr $ Dy (Var "t") A.Plus (Var "t")) - - ,testPassUntouched 7200 performTypeUnification (waitUntil $ exprVariable "t") - ,TestCase $ testPassShouldFail "checkExpressionTest 7201" (performTypeUnification $ waitUntil $ exprVariable "x") state - ,testPassUntouched 7202 performTypeUnification (waitUntil $ buildExpr $ Dy (Var "t") A.Plus (Var "t")) - - ,testPassUntouched 7300 performTypeUnification (altWaitFor (exprVariable "t") $ A.Skip m) - ,TestCase $ testPassShouldFail "checkExpressionTest 7301" (performTypeUnification $ altWaitFor (exprVariable "x") $ A.Skip m) state - ,testPassUntouched 7302 performTypeUnification (altWaitFor (buildExpr $ Dy (Var "t") A.Plus (Var "t")) $ A.Skip m) - - ,testPassUntouched 7400 performTypeUnification (altWaitUntil (exprVariable "t") $ A.Skip m) - ,TestCase $ testPassShouldFail "checkExpressionTest 7401" (performTypeUnification $ altWaitUntil (exprVariable "x") $ A.Skip m) state - ,testPassUntouched 7402 performTypeUnification (altWaitUntil (buildExpr $ Dy (Var "t") A.Plus (Var "t")) $ A.Skip m) - ] - where - -- The type of a timer should not be checked, because it will only have parsed - -- if it used the special name anyway - tim = variable "tim" - getTime :: A.Variable -> A.Process - getTime = A.Input m tim . A.InputTimerRead m . A.InVariable m - waitFor, waitUntil :: A.Expression -> A.Process - waitFor = A.Input m tim . A.InputTimerFor m - waitUntil = A.Input m tim . A.InputTimerAfter m - altWaitFor, altWaitUntil :: A.Expression -> A.Process -> A.Alternative - altWaitFor e body = A.Alternative m (A.True m) tim (A.InputTimerFor m e) body - altWaitUntil e body = A.Alternative m (A.True m) tim (A.InputTimerAfter m e) body - - - testPassUntouched :: Data t => Int -> (t -> PassM t) -> t -> Test - testPassUntouched n passFunc src = TestCase $ testPass ("checkExpressionTest " ++ show n) (mkPattern src) (passFunc src) state - - passAssign :: Int -> String -> ExprHelper -> ExprHelper -> Test - passAssign n lhs exp src = TestCase $ testPassWithCheck ("checkExpressionTest " ++ show n) - (tag3 A.Assign DontCare [variablePattern lhs] $ tag2 A.ExpressionList DontCare [buildExprPattern exp]) - (performTypeUnification $ src') - state refeed - where - src' = A.Assign m [variable lhs] $ A.ExpressionList m [buildExpr src] - - refeed :: A.Process -> Assertion - refeed changed = if (src' /= changed) then testPass ("checkExpressionTest refeed " ++ show n) (mkPattern changed) (performTypeUnification changed) state else return () - - passAssignSame :: Int -> String -> ExprHelper -> Test - passAssignSame n s e = passAssign n s e e - - failAssign :: Int -> String -> ExprHelper -> Test - failAssign n lhs src = TestCase $ testPassShouldFail ("checkExpressionTest " ++ show n) (performTypeUnification $ A.Assign m [variable lhs] $ A.ExpressionList m [buildExpr src]) state - - passWhileIfSame :: Int -> ExprHelper -> Test - passWhileIfSame n e = passWhileIf n e e - - passWhileIf :: Int -> ExprHelper -> ExprHelper -> Test - passWhileIf n exp src = TestList - [ - TestCase $ testPass ("checkExpressionTest/if " ++ show n) - (mIf $ mOnlyC $ tag3 A.Choice DontCare (buildExprPattern exp) (tag1 A.Skip DontCare)) - (performTypeUnification $ A.If m $ A.Only m $ A.Choice m (buildExpr src) (A.Skip m)) - state - ,TestCase $ testPass ("checkExpressionTest/while " ++ show n) - (mWhile (buildExprPattern exp) (tag1 A.Skip DontCare)) - (performTypeUnification $ A.While m (buildExpr src) (A.Skip m)) - state - ] - - failWhileIf :: Int -> ExprHelper -> Test - failWhileIf n src = TestList - [ - TestCase $ testPassShouldFail ("checkExpressionTest/if " ++ show n) - (performTypeUnification $ A.If m $ A.Only m $ A.Choice m (buildExpr src) (A.Skip m)) - state - ,TestCase $ testPassShouldFail ("checkExpressionTest/while " ++ show n) - (performTypeUnification $ A.While m (buildExpr src) (A.Skip m)) - state - ] - - --Takes an index, the inner type of the channel and direction with a variable, then the type and variable for the RHS - --Expects a pass only if the inner type of the channel is the same as the type of the variable, and channel direction is unknown or input - testCheckCommTypesIn :: Int -> (A.Direction,A.Type,A.Variable) -> (A.Type,A.Variable) -> Test - testCheckCommTypesIn n (chanDir,chanType,chanVar) (destType,destVar) - = if (chanType == destType && chanDir /= A.DirOutput) - then TestCase $ testPass ("testCheckCommTypesIn " ++ show n) (mkPattern st) (performTypeUnification st) state - else TestCase $ testPassShouldFail ("testCheckCommTypesIn " ++ show n) (performTypeUnification st) state - where - st = A.Input m chanVar $ A.InputSimple m [A.InVariable m destVar] - - --Takes an index, the inner type of the channel and direction with a variable, then the type and variable for the RHS - --Expects a pass only if the inner type of the channel is the same as the type of the variable, and channel direction is unknown or input - testCheckCommTypesInAlt :: Int -> (A.Direction,A.Type,A.Variable) -> (A.Type,A.Variable) -> Test - testCheckCommTypesInAlt n (chanDir,chanType,chanVar) (destType,destVar) - = if (chanType == destType && chanDir /= A.DirOutput) - then TestCase $ testPass ("testCheckCommTypesIn " ++ show n) (mkPattern st) (performTypeUnification st) state - else TestCase $ testPassShouldFail ("testCheckCommTypesIn " ++ show n) (performTypeUnification st) state - where - st = A.Alt m True $ A.Only m $ A.Alternative m (A.True m) chanVar (A.InputSimple m [A.InVariable m destVar]) $ A.Skip m - - --Automatically tests checking inputs and outputs for various combinations of channel type and direction - testAllCheckCommTypes :: Int -> Test - testAllCheckCommTypes n = TestList $ map (\(n,f) -> f n) $ zip [n..] $ - concat [[\ind -> testCheckCommTypesIn ind c d, \ind -> testCheckCommTypesInAlt ind c d, \ind -> testCheckCommTypesOut ind c d] | c <- chans, d <- vars] - where - chans = concatMap allDirs [(A.Int64,variable "c"), (A.Bool,variable "cb"), (A.Byte, variable "cu8")] - vars = [(A.Bool, variable "b"), (A.Int64, variable "x"), (A.Byte, variable "xu8"), (A.Int16, variable "x16")] - allDirs :: (A.Type,A.Variable) -> [(A.Direction,A.Type,A.Variable)] - allDirs (t,v) = - [ - (A.DirInput,t,A.DirectedVariable m A.DirInput v) - ,(A.DirOutput,t,A.DirectedVariable m A.DirOutput v) - ,(A.DirUnknown,t,v) - ] - - --Takes an index, the inner type of the channel and direction with a variable, then the type and variable for the RHS - --Expects a pass only if the expression type can be cast to the inner type of the channel, and channel direction is unknown or output - testCheckCommTypesOut :: Int -> (A.Direction,A.Type,A.Variable) -> (A.Type,A.Variable) -> Test - testCheckCommTypesOut n (chanDir,chanType,chanVar) (srcType,srcVar) - = if (isImplicitConversionRain srcType chanType && chanDir /= A.DirInput) - then (if srcType == chanType - then TestCase $ testPass ("testCheckCommTypesOut " ++ show n) (mkPattern st) (performTypeUnification st) state - else TestCase $ testPass ("testCheckCommTypesOut " ++ show n) stCast (performTypeUnification st) state - ) - else TestCase $ testPassShouldFail ("testCheckCommTypesOut " ++ show n) (performTypeUnification st) state - where - st = A.Output m chanVar [A.OutExpression m $ A.ExprVariable m srcVar] - stCast = tag3 A.Output DontCare chanVar [tag2 A.OutExpression DontCare $ tag4 A.Conversion DontCare A.DefaultConversion chanType $ - A.ExprVariable m srcVar] - - - passSame :: Int -> A.Type -> ExprHelper -> Test - passSame n t e = pass n t e e - - pass :: Int -> A.Type -> ExprHelper -> ExprHelper -> Test - pass n t exp act = TestCase $ pass' n t (buildExprPattern exp) (buildExpr act) - - -- | To easily get more tests, we take the result of every successful pass (which must be fine now), and feed it back through - --the type-checker to check that it is unchanged - pass' :: Int -> A.Type -> Pattern -> A.Expression -> Assertion - pass' n t exp act = testPassWithCheck ("checkExpressionTest " ++ show n) exp (checkExpressionTypes act) state (check t) - where - check :: A.Type -> A.Expression -> Assertion - check t e - = do eot <- errorOrType - case eot of - Left err -> assertFailure ("checkExpressionTest " ++ show n ++ " astTypeOf failed") - Right t' -> do assertEqual ("checkExpressionTest " ++ show n) t t' - --Now feed it through again, to make sure it isn't changed: - if (e /= act) then pass' (10000 + n) t (mkPattern e) e else return () - where - errorOrType :: IO (Either ErrorReport A.Type) - errorOrType - = (flip runPassM (astTypeOf e) (execState state emptyState)) - >>* \(x,_,_) -> x - - - fail :: Int -> ExprHelper -> Test - fail n e = TestCase $ testPassShouldFail ("checkExpressionTest " ++ show n) (checkExpressionTypes $ buildExpr e) state - - int :: A.Type -> Integer -> ExprHelper - int t n = Lit $ A.Literal m t $ A.IntLiteral m (show n) - - defVar :: String -> A.Type -> State CompState () - defVar n t = defineName (simpleName n) $ simpleDefDecl n t - - state :: State CompState () - state = do defVar "x" A.Int64 - defineConst "X" A.Int64 $ intLiteral 3 - defVar "b" A.Bool - defVar "xu8" A.Byte - defVar "xu16" A.UInt16 - defVar "xu32" A.UInt32 - defVar "xu64" A.UInt64 - defVar "x32" A.Int32 - defVar "x16" A.Int16 - defVar "x8" A.Int8 - defVar "c" $ A.Chan A.DirUnknown (A.ChanAttributes False False) A.Int64 - defVar "cu8" $ A.Chan A.DirUnknown (A.ChanAttributes False False) A.Byte - defVar "cb" $ A.Chan A.DirUnknown (A.ChanAttributes False False) A.Bool - defVar "t" $ A.Time - markRainTest - testUnify :: Test testUnify = TestList [] {- [pass [] [] [] @@ -448,7 +112,6 @@ ioTests :: IO Test ioTests = liftM (TestLabel "RainTypesTest" . TestList) $ sequence [ return constantFoldTest - ,return checkExpressionTest ,return testUnify ,automaticTest FrontendRain "testcases/automatic/unify-types-1.rain.test" ]