1{-# OPTIONS_GHC -Wall #-}
3{-| This module contains checks to be run *after* type inference has completed
4successfully. At that point we still need to do occurs checks and ensure that
5`main` has an acceptable type.
7module Type.ExtraChecks (mainType, occurs, wireTypes) where
9import Prelude hiding (maybe)
10import Control.Applicative ((<$>),(<*>))
11import Control.Monad.Error
12import Control.Monad.State
13import qualified Data.Map as Map
14import qualified Data.Traversable as Traverse
15import qualified Data.UnionFind.IO as UF
16import Text.PrettyPrint as P
18import qualified AST.Annotation as A
19import qualified AST.Expression.Canonical as Canonical
20import qualified AST.PrettyPrint as PP
21import qualified AST.Type as ST
22import qualified AST.Variable as Var
23import qualified Transform.Expression as Expr
24import qualified Type.Hint as Hint
25import qualified Type.Type as TT
26import qualified Type.State as TS
29throw :: [Doc] -> Either [Doc] a
36mainType :: TS.Env -> ErrorT [P.Doc] IO (Map.Map String ST.CanonicalType)
38 do environment' <- liftIO $ Traverse.traverse TT.toSrcType environment
39 mainCheck environment'
44 => Map.Map String ST.CanonicalType
45 -> ErrorT [P.Doc] m (Map.Map String ST.CanonicalType)
47 case Map.lookup "main" env of
52 let tipe = ST.deepDealias typeOfMain
54 if tipe `elem` validMainTypes
56 else throwError [ badMainMessage typeOfMain ]
59validMainTypes :: [ST.CanonicalType]
67 fromModule :: [String] -> String -> ST.CanonicalType
68 fromModule home name =
69 ST.Type (Var.fromModule home name)
72 fromModule ["VirtualDom"] "Node"
75 ST.App (fromModule ["Signal"] "Varying") [ tipe ]
79 ST.Type (Var.builtin name)
82 ST.App (fromModule ["Maybe"] "Maybe") [ tipe ]
85 [ ("element", fromModule ["Graphics","Element"] "ElementPrim")
88 [ ("click" , builtin "_Tuple0")
89 , ("color" , maybe (fromModule ["Color"] "Color"))
90 , ("height" , builtin "Int")
91 , ("hover" , builtin "_Tuple0")
92 , ("href" , builtin "String")
93 , ("id" , builtin "Int")
94 , ("opacity", builtin "Float")
95 , ("tag" , builtin "String")
96 , ("width" , builtin "Int")
104badMainMessage :: ST.CanonicalType -> P.Doc
105badMainMessage typeOfMain =
107 [ P.text "Type Error: 'main' must have one of the following types:"
109 , P.text " Element, Html, Varying Element, Varying Html"
111 , P.text "Instead 'main' has type:\n"
112 , P.nest 4 (PP.pretty typeOfMain)
119data Direction = In | Out
122wireTypes :: (Monad m) => Canonical.Expr -> ErrorT [P.Doc] m ()
124 case Expr.checkWires (checkWires In) (checkWires Out) checkLoobacks expr of
125 Left err -> throwError err
129checkWires :: Direction -> String -> ST.CanonicalType -> Either [P.Doc] ()
130checkWires direction name tipe =
131 checkWiresHelp direction name tipe tipe
140checkWiresHelp direction name rootType tipe =
142 ST.Aliased _ args t ->
143 checkWiresHelp direction name rootType (ST.dealias args t)
145 ST.App (ST.Type signal) [t]
146 | Var.isStream signal ->
147 validWireType False (Just Stream) direction name rootType t
149 | Var.isVarying signal ->
150 validWireType False (Just Varying) direction name rootType t
153 validWireType False Nothing direction name rootType tipe
156data Signal = Stream | Varying
167validWireType seenFunc seenSignal direction name rootType tipe =
168 let valid localType =
169 validWireType seenFunc seenSignal direction name rootType localType
172 throw (wireError name direction rootType tipe kind)
175 ST.Aliased _ args t ->
176 valid (ST.dealias args t)
179 case any ($ v) [ Var.isJson, Var.isPrimitive, Var.isTuple ] of
181 False -> err "It contains an unsupported type"
186 ST.App (ST.Type v) [t]
187 | Var.isMaybe v -> valid t
188 | Var.isArray v -> valid t
189 | Var.isList v -> valid t
191 ST.App (ST.Type v) ts
192 | Var.isTuple v -> mapM_ valid ts
195 err "It contains an unsupported type"
198 err "It contains a free type variable"
202 In -> err "It contains functions"
205 then err "It contains higher-order functions"
209 err "It is a streams that contains a function"
212 err "It is a varying value that contains a function"
215 forM_ (ST.collectLambdas tipe)
216 (validWireType True seenSignal direction name rootType)
218 ST.Record _ (Just _) ->
219 err "It contains extended records with free type variables"
221 ST.Record fields Nothing ->
222 mapM_ (\(k,v) -> (,) k <$> valid v) fields
232wireError name direction rootType localType problemMessage =
233 [ P.text (dir "Input" "Output" ++ " Error:")
236 [ txt [ "The ", wire, " named '", name, "' has an invalid type.\n" ]
237 , P.nest 4 (PP.pretty rootType) <> P.text "\n"
238 , txt [ problemMessage, ":\n" ]
239 , P.nest 4 (PP.pretty localType) <> P.text "\n"
240 , txt [ "Acceptable values for ", wire, "s include:" ]
241 , txt [ " Ints, Floats, Bools, Strings, Maybes, Lists, Arrays, Tuples, unit values," ]
242 , txt [ " Json.Values, ", dir "" "first-order functions, promises, ", "and concrete records." ]
251 txt = P.text . concat
257checkLoobacks :: String -> ST.CanonicalType -> Bool -> Either [P.Doc] ()
258checkLoobacks name tipe hasExpr =
259 checkLoobacksHelp name tipe tipe hasExpr
262checkLoobacksHelp :: String -> ST.CanonicalType -> ST.CanonicalType -> Bool -> Either [P.Doc] ()
263checkLoobacksHelp name rootType tipe hasExpr =
264 case ST.deepDealias tipe of
266 [ ("mailbox", ST.App (ST.Type mailbox) [a])
267 , ("stream", ST.App (ST.Type stream) [b])
271 && Var.isStream stream
272 && Var.isMailbox mailbox
277 ST.App (ST.Type signal) [ ST.App (ST.Type result) [_,_] ]
278 | hasExpr && Var.isStream signal && Var.isResult result ->
283 [ P.text "Loopback Error:"
286 [ P.text ("The loopback named '" ++ name ++ "' has an invalid type.\n")
287 , P.nest 4 (PP.pretty rootType) <> P.text "\n"
294occurs :: (String, TT.Variable) -> StateT TS.SolverState IO ()
295occurs (name, variable) =
296 do vars <- liftIO $ infiniteVars [] variable
302 do desc <- liftIO $ UF.descriptor var
303 case TT.structure desc of
305 TS.addHint (P.text msg)
308 do liftIO $ UF.setDescriptor var (desc { TT.structure = Nothing })
309 var' <- liftIO $ UF.fresh desc
310 hint <- liftIO $ Hint.create (A.None (P.text name)) (Just msg) var var'
313 msg = "Infinite types are not allowed"
315 infiniteVars :: [TT.Variable] -> TT.Variable -> IO [TT.Variable]
316 infiniteVars seen var =
317 let go = infiniteVars (var:seen) in
321 desc <- UF.descriptor var
322 case TT.structure desc of
327 (++) <$> go a <*> go b
330 (++) <$> go a <*> go b
338 TT.Record1 fields ext ->
339 concat <$> mapM go (ext : concat (Map.elems fields))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list