on master help sign in
Move the occurs check into its own module

Preparing to fix a bug!

commit368cdbc3d97f238e3954026cd9d21bb5d7986fc8 authorEvan Czaplicki <evancz@users.noreply.github.com> dateThu 1 Jun 2017, 23:34 (9 years ago) parent20fa5f2
3 files changed+61−42
elm-compiler.cabal+1 src/Type/Occurs.hs+58 src/Type/Solve.hs+2−42
elm-compiler.cabal+1
@@ -139,6 +139,7 @@ Library
139139 Type.Constrain.Pattern,
140140 Type.Environment,
141141 Type.Inference,
142+ Type.Occurs,
142143 Type.Solve,
143144 Type.State,
144145 Type.Type,
src/Type/Occurs.hsnew file+58
@@ -0,0 +1,58 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+module Type.Occurs (occurs) where
4+
5+import qualified Data.Map as Map
6+
7+import Type.Type as Type
8+import qualified Type.UnionFind as UF
9+
10+
11+
12+-- OCCURS
13+
14+
15+occurs :: Type.Variable -> IO Bool
16+occurs var =
17+ occursHelp [] var
18+
19+
20+occursHelp :: [Type.Variable] -> Type.Variable -> IO Bool
21+occursHelp seen var =
22+ if elem var seen then
23+ do infiniteDescriptor <- UF.descriptor var
24+ UF.setDescriptor var (infiniteDescriptor { _content = Error })
25+ return True
26+
27+ else
28+ do desc <- UF.descriptor var
29+ case _content desc of
30+ Atom _ ->
31+ return False
32+
33+ Var _ _ _ ->
34+ return False
35+
36+ Error ->
37+ return False
38+
39+ Alias _ args _ ->
40+ -- TODO is it okay to only check args?
41+ or <$> traverse (occursHelp (var:seen) . snd) args
42+
43+ Structure term ->
44+ let
45+ go = occursHelp (var:seen)
46+ in
47+ case term of
48+ App1 a b ->
49+ (||) <$> go a <*> go b
50+
51+ Fun1 a b ->
52+ (||) <$> go a <*> go b
53+
54+ EmptyRecord1 ->
55+ return False
56+
57+ Record1 fields ext ->
58+ or <$> traverse go (ext : Map.elems fields)
src/Type/Solve.hs+2−42
@@ -11,6 +11,7 @@ import qualified Data.Text as Text
1111import qualified AST.Module.Name as ModuleName
1212import qualified Reporting.Annotation as A
1313import qualified Reporting.Error.Type as Error
14+import qualified Type.Occurs as Occurs
1415import qualified Type.State as TS
1516import Type.Type as Type
1617import Type.Unify
@@ -268,7 +269,7 @@ crash msg =
268269occurs :: (Text.Text, A.Located Variable) -> TS.Solver ()
269270occurs (name, A.A region variable) =
270271 {-# SCC elm_compiler_type_occurs #-}
271− do hasOccurred <- liftIO $ occursHelp [] variable
272+ do hasOccurred <- liftIO $ Occurs.occurs variable
272273 case hasOccurred of
273274 False ->
274275 return ()
@@ -276,44 +277,3 @@ occurs (name, A.A region variable) =
276277 True ->
277278 do overallType <- liftIO (Type.toSrcType variable)
278279 TS.addError region (Error.InfiniteType name overallType)
279−
280−
281−occursHelp :: [Variable] -> Variable -> IO Bool
282−occursHelp seen var =
283− if elem var seen then
284− do infiniteDescriptor <- UF.descriptor var
285− UF.setDescriptor var (infiniteDescriptor { _content = Error })
286− return True
287−
288− else
289− do desc <- UF.descriptor var
290− case _content desc of
291− Atom _ ->
292− return False
293−
294− Var _ _ _ ->
295− return False
296−
297− Error ->
298− return False
299−
300− Alias _ args _ ->
301− -- TODO is it okay to only check args?
302− or <$> mapM (occursHelp (var:seen) . snd) args
303−
304− Structure term ->
305− let
306− go = occursHelp (var:seen)
307− in
308− case term of
309− App1 a b ->
310− (||) <$> go a <*> go b
311−
312− Fun1 a b ->
313− (||) <$> go a <*> go b
314−
315− EmptyRecord1 ->
316− return False
317−
318− Record1 fields ext ->
319− or <$> mapM go (ext : Map.elems fields)