@@ -42,10 +42,11 @@ module Language.PureScript.TypeChecker.Types (
44import Data.List
44import Data.List
45−import Data.Maybe (maybeToList, isNothing, isJust, fromMaybe)
45+import Data.Maybe (maybeToList, fromMaybe)
46import Data.Function (on)
46import Data.Function (on)
47import Data.Ord (comparing)
47import Data.Ord (comparing)
48import Data.Monoid
48import Data.Monoid
49+import Data.Either (lefts, rights)
50import Language.PureScript.Declarations
51import Language.PureScript.Declarations
51import Language.PureScript.Types
52import Language.PureScript.Types
@@ -171,14 +172,16 @@ unifyRows r1 r2 =
171typesOf :: Maybe ModuleName -> ModuleName -> [(Ident, Expr)] -> Check [(Ident, (Expr, Type))]
172typesOf :: Maybe ModuleName -> ModuleName -> [(Ident, Expr)] -> Check [(Ident, (Expr, Type))]
172typesOf mainModuleName moduleName vals = do
173typesOf mainModuleName moduleName vals = do
173 tys <- fmap tidyUp . liftUnify $ do
174 tys <- fmap tidyUp . liftUnify $ do
174− (es, dict, untypedDict) <- typeDictionaryForBindingGroup moduleName vals
175+ (untyped, typed, dict, untypedDict) <- typeDictionaryForBindingGroup moduleName vals
175− forM es $ \e -> do
176+ ds1 <- parU typed $ \e -> do
176− triple@(_, (_, ty)) <- typeForBindingGroupElement moduleName e dict untypedDict
177+ triple@(_, (_, ty)) <- checkTypedBindingGroupElement moduleName e dict
177− -- If --main is enabled, need to check that `main` has type Eff eff a for some eff, a
178+ checkMain (fst e) ty
178− when (Just moduleName == mainModuleName && fst e == Ident C.main) $ do
179− [eff, a] <- replicateM 2 fresh
180− ty =?= TypeApp (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Control", ProperName "Monad", ProperName "Eff"])) (ProperName "Eff"))) eff) a
181 return triple
179 return triple
180+ ds2 <- forM untyped $ \e -> do
181+ triple@(_, (_, ty)) <- typeForBindingGroupElement e dict untypedDict
182+ checkMain (fst e) ty
183 forM tys $ \(ident, (val, ty)) -> do
186 forM tys $ \(ident, (val, ty)) -> do
184 -- Replace type class dictionary placeholders with actual dictionaries
187 -- Replace type class dictionary placeholders with actual dictionaries
@@ -193,17 +196,25 @@ typesOf mainModuleName moduleName vals = do
194 -- Apply the substitution that was returned from runUnify to both types and (type-annotated) values
197 -- Apply the substitution that was returned from runUnify to both types and (type-annotated) values
195 tidyUp (ts, sub) = map (\(i, (val, ty)) -> (i, (overTypes (sub $?) val, sub $? ty))) ts
198 tidyUp (ts, sub) = map (\(i, (val, ty)) -> (i, (overTypes (sub $?) val, sub $? ty))) ts
199+ -- If --main is enabled, need to check that `main` has type Eff eff a for some eff, a
200+ checkMain nm ty = when (Just moduleName == mainModuleName && nm == Ident C.main) $ do
201+ [eff, a] <- replicateM 2 fresh
202+ ty =?= TypeApp (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Control", ProperName "Monad", ProperName "Eff"])) (ProperName "Eff"))) eff) a
204+type TypeData = M.Map (ModuleName, Ident) (Type, NameKind, NameVisibility)
206+type UntypedData = [(Ident, Type)]
197−typeDictionaryForBindingGroup :: ModuleName -> [(Ident, Expr)] -> UnifyT Type Check ([(Ident, (Expr, Maybe (Type, Bool)))], M.Map (ModuleName, Ident) (Type, NameKind, NameVisibility), [(Ident, Type)])
208+typeDictionaryForBindingGroup :: ModuleName -> [(Ident, Expr)] -> UnifyT Type Check ([(Ident, Expr)], [(Ident, (Expr, Type, Bool))], TypeData, UntypedData)
198typeDictionaryForBindingGroup moduleName vals = do
209typeDictionaryForBindingGroup moduleName vals = do
200 -- Map each declaration to a name/value pair, with an optional type, if the declaration is typed
211 -- Map each declaration to a name/value pair, with an optional type, if the declaration is typed
201 es = map isTyped vals
212 es = map isTyped vals
202 -- Filter the typed and untyped declarations
213 -- Filter the typed and untyped declarations
203− typed = filter (isJust . snd . snd) es
214+ untyped = lefts es
204− untyped = filter (isNothing . snd . snd) es
215+ typed = rights es
205 -- Make a map of names to typed declarations
216 -- Make a map of names to typed declarations
206− typedDict = map (\(ident, (_, Just (ty, _))) -> (ident, ty)) typed
217+ typedDict = map (\(ident, (_, ty, _)) -> (ident, ty)) typed
208 -- Create fresh unification variables for the types of untyped declarations
219 -- Create fresh unification variables for the types of untyped declarations
209 untypedNames <- replicateM (length untyped) fresh
220 untypedNames <- replicateM (length untyped) fresh
@@ -213,37 +224,33 @@ typeDictionaryForBindingGroup moduleName vals = do
213 untypedDict = zip (map fst untyped) untypedNames
224 untypedDict = zip (map fst untyped) untypedNames
214 -- Create the dictionary of all name/type pairs, which will be added to the environment during type checking
225 -- Create the dictionary of all name/type pairs, which will be added to the environment during type checking
215 dict = M.fromList (map (\(ident, ty) -> ((moduleName, ident), (ty, LocalVariable, Undefined))) $ typedDict ++ untypedDict)
226 dict = M.fromList (map (\(ident, ty) -> ((moduleName, ident), (ty, LocalVariable, Undefined))) $ typedDict ++ untypedDict)
216− return (es, dict, untypedDict)
227+ return (untyped, typed, dict, untypedDict)
218−typeForBindingGroupElement :: ModuleName -> (Ident, (Expr, Maybe (Type, Bool))) -> M.Map (ModuleName, Ident) (Type, NameKind, NameVisibility) -> [(Ident, Type)] -> UnifyT Type Check (Ident, (Expr, Type))
229+checkTypedBindingGroupElement :: ModuleName -> (Ident, (Expr, Type, Bool)) -> TypeData -> UnifyT Type Check (Ident, (Expr, Type))
219−typeForBindingGroupElement moduleName el dict untypedDict =
220− -- If the declaration is a function, it has access to other values in the binding group.
221− -- If not, the generated code might fail at runtime since those values might be undefined.
223− -- Typed declarations
224− (ident, (val', Just (ty, checkType))) -> do
230+checkTypedBindingGroupElement moduleName (ident, (val', ty, checkType)) dict = do
225− -- Kind check
231+ -- Kind check
226− kind <- liftCheck $ kindOf moduleName ty
232+ kind <- liftCheck $ kindOf moduleName ty
227− guardWith (strMsg $ "Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
233+ guardWith (strMsg $ "Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
228− -- Check the type with the new names in scope
234+ -- Check the type with the new names in scope
229− ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty
235+ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty
230− val'' <- if checkType
236+ val'' <- if checkType
231− then bindNames dict $ TypedValue True <$> check val' ty' <*> pure ty'
237+ then bindNames dict $ TypedValue True <$> check val' ty' <*> pure ty'
232− else return (TypedValue False val' ty')
238+ else return (TypedValue False val' ty')
233− return (ident, (val'', ty'))
239+ return (ident, (val'', ty'))
234− -- Untyped declarations
240+
235− (ident, (val', Nothing)) -> do
241+typeForBindingGroupElement :: (Ident, Expr) -> TypeData -> UntypedData -> UnifyT Type Check (Ident, (Expr, Type))
242+typeForBindingGroupElement (ident, val) dict untypedDict = do
236− -- Infer the type with the new names in scope
243+ -- Infer the type with the new names in scope
237− TypedValue _ val'' ty <- bindNames dict $ infer val'
244+ TypedValue _ val' ty <- bindNames dict $ infer val
238− ty =?= fromMaybe (error "name not found in dictionary") (lookup ident untypedDict)
245+ ty =?= fromMaybe (error "name not found in dictionary") (lookup ident untypedDict)
239− return (ident, (TypedValue True val'' ty, ty))
246+ return (ident, (TypedValue True val' ty, ty))
242-- Check if a value contains a type annotation
249-- Check if a value contains a type annotation
244−isTyped :: (Ident, Expr) -> (Ident, (Expr, Maybe (Type, Bool)))
251+isTyped :: (Ident, Expr) -> (Either (Ident, Expr) (Ident, (Expr, Type, Bool)))
245−isTyped (name, TypedValue checkType value ty) = (name, (value, Just (ty, checkType)))
252+isTyped (name, TypedValue checkType value ty) = Right (name, (value, ty, checkType))
246−isTyped (name, value) = (name, (value, Nothing))
253+isTyped (name, value) = Left (name, value)
249-- Map a function over type annotations appearing inside a value
256-- Map a function over type annotations appearing inside a value
@@ -655,8 +662,8 @@ infer' (IfThenElse cond th el) = do
655 cond' <- check cond tyBoolean
662 cond' <- check cond tyBoolean
656 v2@(TypedValue _ _ t2) <- infer th
663 v2@(TypedValue _ _ t2) <- infer th
657 v3@(TypedValue _ _ t3) <- infer el
664 v3@(TypedValue _ _ t3) <- infer el
658− t2 =?= t3
665+ (v2', v3', t) <- meet v2 v3 t2 t3
659− return $ TypedValue True (IfThenElse cond' v2 v3) t2
666+ return $ TypedValue True (IfThenElse cond' v2' v3') t
660infer' (Let ds val) = do
667infer' (Let ds val) = do
661 (ds', val'@(TypedValue _ _ valTy)) <- inferLetBinding [] ds val infer
668 (ds', val'@(TypedValue _ _ valTy)) <- inferLetBinding [] ds val infer
662 return $ TypedValue True (Let ds' val') valTy
669 return $ TypedValue True (Let ds' val') valTy
@@ -692,10 +699,10 @@ inferLetBinding seen (ValueDeclaration ident nameKind [] Nothing val : rest) ret
692 bindNames (M.singleton (moduleName, ident) (valTy', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] Nothing val']) rest ret j
699 bindNames (M.singleton (moduleName, ident) (valTy', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] Nothing val']) rest ret j
693inferLetBinding seen (BindingGroupDeclaration ds : rest) ret j = do
700inferLetBinding seen (BindingGroupDeclaration ds : rest) ret j = do
694 Just moduleName <- checkCurrentModule <$> get
701 Just moduleName <- checkCurrentModule <$> get
695− (es, dict, untypedDict) <- typeDictionaryForBindingGroup moduleName (map (\(i, _, v) -> (i, v)) ds)
702+ (untyped, typed, dict, untypedDict) <- typeDictionaryForBindingGroup moduleName (map (\(i, _, v) -> (i, v)) ds)
696− ds' <- forM es $ \e -> do
703+ ds1' <- parU typed $ \e -> checkTypedBindingGroupElement moduleName e dict
697− (ident, (val', _)) <- typeForBindingGroupElement moduleName e dict untypedDict
704+ ds2' <- forM untyped $ \e -> typeForBindingGroupElement e dict untypedDict
698− return $ (ident, LocalVariable, val')
705+ let ds' = [(ident, LocalVariable, val') | (ident, (val', _)) <- ds1' ++ ds2']
699 makeBindingGroupVisible $ bindNames dict $ inferLetBinding (seen ++ [BindingGroupDeclaration ds']) rest ret j
706 makeBindingGroupVisible $ bindNames dict $ inferLetBinding (seen ++ [BindingGroupDeclaration ds']) rest ret j
700inferLetBinding seen (PositionedDeclaration pos d : ds) ret j = rethrowWithPosition pos $ do
707inferLetBinding seen (PositionedDeclaration pos d : ds) ret j = rethrowWithPosition pos $ do
701 ((d' : ds'), val') <- inferLetBinding seen (d : ds) ret j
708 ((d' : ds'), val') <- inferLetBinding seen (d : ds) ret j
@@ -1119,6 +1126,22 @@ subsumes' val ty1 ty2 = do
1119 ty1 =?= ty2
1126 ty1 =?= ty2
1120 return val
1127 return val
1130+-- Compute the meet of two types, i.e. the most general type which both types subsume.
1131+-- TODO: handle constrained types
1133+meet :: Expr -> Expr -> Type -> Type -> UnifyT Type Check (Expr, Expr, Type)
1134+meet e1 e2 (ForAll ident t1 _) t2 = do
1135+ t1' <- replaceVarWithUnknown ident t1
1137+meet e1 e2 t1 (ForAll ident t2 _) = do
1138+ t2' <- replaceVarWithUnknown ident t2
1140+meet e1 e2 t1 t2 = do
1142+ return (e1, e2, t1)