on master help sign in
Merge branch 'master' into dev
commitac71ab1fd866717f52f2a26a8efccdbf47893c82 authorEvan Czaplicki <info@elm-lang.org> dateWed 21 Aug 2013, 20:06 (13 years ago) parentb5979b418c67cb
13 files changed+205−52
Elm.cabal+2 changelog.txt+8 compiler/Compiler.hs+6−7 compiler/Initialize.hs−1 compiler/SourceSyntax/Module.hs+1−2 compiler/SourceSyntax/Type.hs+12−1 compiler/Type/Alias.hs+119 compiler/Type/ExtraChecks.hs+24−12 compiler/Type/Inference.hs+7−7 compiler/Type/State.hs+15−10 libraries/Color.elm+9−9 libraries/Graphics/Collage.elm+1−1 libraries/Graphics/Input.elm+1−2
Elm.cabal+2
@@ -63,6 +63,7 @@ Library
6363 Parse.Parse,
6464 Parse.Pattern,
6565 Parse.Type,
66+ Type.Alias,
6667 Type.Constrain.Declaration,
6768 Type.Constrain.Expression,
6869 Type.Constrain.Literal,
@@ -132,6 +133,7 @@ Executable elm
132133 Parse.Parse,
133134 Parse.Pattern,
134135 Parse.Type,
136+ Type.Alias,
135137 Type.Constrain.Declaration,
136138 Type.Constrain.Expression,
137139 Type.Constrain.Literal,
changelog.txt+8
@@ -1,4 +1,12 @@
11
2+Release 0.9.1
3+=============
4+
5+ * Switch to Tango color scheme, adding a bunch of nice colors
6+ * add the greyscale function for easily producing greys
7+ * Fix miscellaneous bugs in type checker
8+ * Switch name of Matrix2D to Transform2D
9+
210Release 0.9
311===========
412
compiler/Compiler.hs+6−7
@@ -31,7 +31,7 @@ import Paths_Elm
3131import SourceSyntax.PrettyPrint (pretty, variable)
3232import Text.PrettyPrint as P
3333import qualified Type.Type as Type
34−import qualified Data.Traversable as Traverse
34+import qualified Type.Alias as Alias
3535
3636data Flags =
3737 Flags { make :: Bool
@@ -146,10 +146,9 @@ buildFile flags moduleNum numModules interfaces filePath =
146146 True -> print . pretty $ program modul
147147 return modul
148148
149− if print_types flags then printTypes metaModule else return ()
150− tipes <- Traverse.traverse Type.toSrcType (types metaModule)
149+ if print_types flags then printTypes interfaces metaModule else return ()
151150 let interface = Canonical.interface name $ ModuleInterface {
152− iTypes = tipes,
151+ iTypes = types metaModule,
153152 iAdts = datatypes metaModule,
154153 iAliases = aliases metaModule
155154 }
@@ -160,11 +159,11 @@ buildFile flags moduleNum numModules interfaces filePath =
160159 writeFile (elmo flags filePath) (jsModule metaModule)
161160 return (name,interface)
162161
163−printTypes metaModule = do
162+printTypes interfaces metaModule = do
164163 putStrLn ""
164+ let rules = Alias.rules interfaces metaModule
165165 forM_ (Map.toList $ types metaModule) $ \(n,t) -> do
166− pt <- Type.extraPretty t
167− print $ variable n <+> P.text ":" <+> pt
166+ print $ variable n <+> P.text ":" <+> pretty (Alias.realias rules t)
168167 putStrLn ""
169168
170169getRuntime :: Flags -> IO FilePath
compiler/Initialize.hs−1
@@ -11,7 +11,6 @@ import System.FilePath as FP
1111import Text.PrettyPrint (Doc)
1212
1313import SourceSyntax.Everything
14−import SourceSyntax.Type
1514import qualified Parse.Parse as Parse
1615import qualified Metadata.Prelude as Prelude
1716import qualified Transform.Check as Check
compiler/SourceSyntax/Module.hs+1−2
@@ -12,7 +12,6 @@ import SourceSyntax.Expression (LExpr)
1212import SourceSyntax.Declaration
1313import SourceSyntax.Type
1414import System.FilePath (joinPath)
15−import qualified Type.Type as Type
1615
1716data Module tipe var =
1817 Module [String] Exports Imports [Declaration tipe var]
@@ -30,7 +29,7 @@ data MetadataModule t v = MetadataModule {
3029 exports :: [String],
3130 imports :: [(String, ImportMethod)],
3231 program :: LExpr t v,
33− types :: Map.Map String Type.Variable,
32+ types :: Map.Map String Type,
3433 fixities :: [(Assoc, Int, String)],
3534 aliases :: [(String, [String], Type)],
3635 datatypes :: [ (String, [String], [(String,[Type])]) ],
compiler/SourceSyntax/Type.hs+12−1
@@ -41,8 +41,11 @@ instance Pretty Type where
4141 | Help.isTuple name -> P.parens . P.sep . P.punctuate P.comma $ map pretty tipes
4242 | otherwise -> P.hang (P.text name) 2 (P.sep $ map prettyParens tipes)
4343 EmptyRecord -> P.braces P.empty
44− Record fields ext -> P.braces $ P.hang (pretty ext <+> P.text "|") 4 prettyFields
44+ Record _ _ -> P.braces $ case ext of
45+ EmptyRecord -> prettyFields
46+ _ -> P.hang (pretty ext <+> P.text "|") 4 prettyFields
4547 where
48+ (fields, ext) = collectRecords tipe
4649 prettyField (f,t) = P.text f <+> P.text ":" <+> pretty t
4750 prettyFields = commaSep . map prettyField $ fields
4851
@@ -52,11 +55,19 @@ collectLambdas tipe =
5255 Lambda arg body -> pretty arg : collectLambdas body
5356 _ -> [pretty tipe]
5457
58+collectRecords = go []
59+ where
60+ go fields tipe =
61+ case tipe of
62+ Record fs ext -> go (fs ++ fields) ext
63+ _ -> (fields, tipe)
64+
5565prettyParens tipe = parensIf needed (pretty tipe)
5666 where
5767 needed =
5868 case tipe of
5969 Lambda _ _ -> True
70+ Data "_List" [_] -> False
6071 Data _ [] -> False
6172 Data _ _ -> True
6273 _ -> False
compiler/Type/Alias.hsnew file+119
@@ -0,0 +1,119 @@
1+module Type.Alias (realias, rules, canonicalRealias, Rules) where
2+
3+import Control.Applicative ((<$>),(<*>))
4+import Control.Monad
5+import Control.Arrow (second)
6+import Data.Map ((!))
7+import qualified Data.Map as Map
8+import qualified Data.List as List
9+import SourceSyntax.Type
10+import SourceSyntax.Module
11+
12+type Rules = ([(String,[String],Type)], Type -> Type)
13+
14+rules interfaces metaModule = (collect interfaces metaModule, localizer metaModule)
15+
16+collect interfaces metaModule = filter (not . isPrimitive) rawAliases
17+ where
18+ rawAliases = aliases metaModule ++ concatMap iAliases (Map.elems interfaces)
19+
20+ isPrimitive (_,_,tipe) =
21+ case tipe of
22+ Data _ [] -> True
23+ _ -> False
24+
25+localizer metaModule = go
26+ where
27+ go tipe =
28+ case tipe of
29+ Var _ -> tipe
30+ EmptyRecord -> tipe
31+ Lambda t1 t2 -> Lambda (go t1) (go t2)
32+ Data name ts -> Data (localize name) (map go ts)
33+ Record fs ext -> Record (map (second go) fs) (go ext)
34+
35+ byMethod = foldr (\(n,m) d -> Map.insertWith (++) n [m] d) Map.empty (imports metaModule)
36+
37+ separate name =
38+ case List.elemIndices '.' name of
39+ [] -> ("",name)
40+ is -> let i = last is in
41+ (take i name, drop (i+1) name)
42+
43+ shortest = List.minimumBy (\a b -> compare (length a) (length b))
44+
45+ localize name = shortest (name : concatMap (localize' value) methods)
46+ where (modul, value) = separate name
47+ methods = Map.findWithDefault [] modul byMethod
48+
49+ localize' name method =
50+ case method of
51+ As modul -> [modul ++ "." ++ name]
52+ Hiding xs | name `notElem` xs -> [name]
53+ Importing xs | name `elem` xs -> [name]
54+ _ -> []
55+
56+realias :: Rules -> Type -> Type
57+realias (aliases,localize) tipe = localize (canonicalRealias aliases tipe)
58+
59+canonicalRealias :: [(String,[String],Type)] -> Type -> Type
60+canonicalRealias aliases tipe =
61+ case concatMap tryRealias aliases of
62+ [tipe''] -> f tipe''
63+ _ -> if tipe == tipe' then tipe else f tipe'
64+ where
65+ tryRealias (name, args, t) =
66+ case diff t tipe of
67+ Nothing -> []
68+ Just kvs ->
69+ let holes = collectFields kvs
70+ hasArgs = List.sort args == Map.keys holes
71+ isConsistent = all allEqual (Map.elems holes)
72+ in case hasArgs && isConsistent of
73+ False -> []
74+ True -> [Data name $ map (\arg -> head (holes ! arg)) args]
75+
76+ f = canonicalRealias aliases
77+ tipe' =
78+ case tipe of
79+ Var _ -> tipe
80+ EmptyRecord -> tipe
81+ Lambda t1 t2 -> Lambda (f t1) (f t2)
82+ Data name ts -> Data name (map f ts)
83+ Record fs ext -> Record (map (second f) fs) (f ext)
84+
85+allEqual [] = True
86+allEqual (x:xs) = all (==x) xs
87+
88+diff :: Type -> Type -> Maybe [(String,Type)]
89+diff general specific =
90+ case (general, specific) of
91+ (Lambda g1 g2, Lambda s1 s2) -> (++) <$> diff g1 s1 <*> diff g2 s2
92+ (Var x, t) -> Just [(x,t)]
93+ (Data gname gts, Data sname sts)
94+ | gname == sname && length gts == length sts ->
95+ concat <$> zipWithM diff gts sts
96+ (EmptyRecord, EmptyRecord) -> Just []
97+ (Record _ _, Record _ _) ->
98+ let (gfs,gext) = collectRecords general
99+ (sfs,sext) = collectRecords specific
100+ gfields = collectFields gfs
101+ sfields = collectFields sfs
102+
103+ overlap = Map.intersectionWith (\gs ss -> length gs == length ss) sfields gfields
104+ isAligned = Map.size gfields == Map.size overlap && and (Map.elems overlap)
105+ in
106+ case isAligned of
107+ False -> Nothing
108+ True -> let remaining = Map.difference sfields gfields
109+ sext' = if Map.null remaining then sext else
110+ Record (flattenFields remaining) sext
111+ matchMap = Map.intersectionWith (zipWith diff) gfields sfields
112+ in concat <$> sequence (diff gext sext' : concat (Map.elems matchMap))
113+ (_,_) -> Nothing
114+
115+collectFields fields =
116+ foldr (\(f,t) fs -> Map.insertWith (++) f [t] fs) Map.empty fields
117+
118+flattenFields fields =
119+ concatMap (\(f,ts) -> map ((,) f) ts) (Map.toList fields)
compiler/Type/ExtraChecks.hs+24−12
@@ -6,26 +6,38 @@ module Type.ExtraChecks (extraChecks) where
66import Control.Applicative ((<$>),(<*>))
77import qualified Data.Map as Map
88import qualified Data.UnionFind.IO as UF
9−import Type.Type ( Variable, structure, Term1(..) )
9+import Type.Type ( Variable, structure, Term1(..), toSrcType )
1010import Type.State (Env)
11−import Type.PrettyPrint ( pretty, ParensWhen(Never) )
11+import qualified Type.Alias as Alias
1212import Text.PrettyPrint as P
13+import SourceSyntax.PrettyPrint (pretty)
14+import SourceSyntax.Type (Type)
15+import qualified Data.Traversable as Traverse
1316
14−extraChecks :: Env -> IO (Either [P.Doc] Env)
15−extraChecks env =
16− case mainCheck env of
17− Left errs -> return $ Left errs
18− Right env -> occursCheck env
17+extraChecks :: Alias.Rules -> Env -> IO (Either [P.Doc] (Map.Map String Type))
18+extraChecks rules env = do
19+ eitherEnv <- occursCheck env
20+ case eitherEnv of
21+ Left errs -> return $ Left errs
22+ Right env' ->
23+ mainCheck rules <$> Traverse.traverse toSrcType env'
24+
1925
20−mainCheck :: Env -> Either [P.Doc] Env
21−mainCheck env =
26+mainCheck :: Alias.Rules -> (Map.Map String Type) -> Either [P.Doc] (Map.Map String Type)
27+mainCheck rules env =
28+ let acceptable = ["Graphics.Element.Element","Signal.Signal Graphics.Element.Element"] in
2229 case Map.lookup "main" env of
2330 Nothing -> Right env
24− Just var
25− | P.render (pretty Never var) `elem` ["Element","Signal Element"] -> Right env
31+ Just tipe
32+ | P.render (pretty (Alias.canonicalRealias (fst rules) tipe)) `elem` acceptable ->
33+ Right env
2634 | otherwise ->
2735 Left [ P.vcat [ P.text "Type Error:"
28− , P.text "'main' must be an Element or a (Signal Element)\n" ] ]
36+ , P.text "Bad type for 'main'. It must have type Element or a (Signal Element)"
37+ , P.text "Instead 'main' has type:\n"
38+ , P.nest 4 . pretty $ Alias.realias rules tipe
39+ , P.text " " ]
40+ ]
2941
3042occursCheck :: Env -> IO (Either [P.Doc] Env)
3143occursCheck env = do
compiler/Type/Inference.hs+7−7
@@ -12,18 +12,19 @@ import SourceSyntax.Module as Module
1212import qualified SourceSyntax.Expression as Expr
1313import SourceSyntax.Location (Located, noneNoDocs)
1414import SourceSyntax.PrettyPrint
15+import SourceSyntax.Type (Type)
1516import Text.PrettyPrint
1617import qualified Type.State as TS
1718import Type.ExtraChecks (extraChecks)
1819import Control.Monad.State
1920import Control.Arrow (second)
20−import Transform.SortDefinitions as Sort
21+import qualified Type.Alias as Alias
2122
2223import System.IO.Unsafe -- Possible to switch over to the ST monad instead of
2324 -- the IO monad. I don't think that'd be worthwhile.
2425
2526
26−infer :: Interfaces -> MetadataModule t v -> Either [Doc] (Map.Map String T.Variable)
27+infer :: Interfaces -> MetadataModule t v -> Either [Doc] (Map.Map String Type)
2728infer interfaces modul = unsafePerformIO $ do
2829 env <- Env.initialEnvironment
2930 (datatypes modul ++ concatMap iAdts (Map.elems interfaces))
@@ -45,8 +46,7 @@ infer interfaces modul = unsafePerformIO $ do
4546 constraint <- environ `fmap` TcExpr.constrain env (program modul) (T.VarN fvar)
4647
4748 state <- execStateT (Solve.solve constraint) TS.initialState
48− let errors = TS.sErrors state
49− if null errors
50− then extraChecks $ Map.difference (TS.sSavedEnv state) header
51− else Left `fmap` sequence (reverse errors)
52−
49+ let rules = Alias.rules interfaces modul
50+ case TS.sErrors state of
51+ errors@(_:_) -> Left `fmap` sequence (map ($ rules) (reverse errors))
52+ [] -> extraChecks rules (Map.difference (TS.sSavedEnv state) header)
compiler/Type/State.hs+15−10
@@ -11,6 +11,8 @@ import qualified Data.Traversable as Traversable
1111import Text.PrettyPrint as P
1212import SourceSyntax.PrettyPrint
1313import SourceSyntax.Location
14+import qualified SourceSyntax.Type as Src
15+import qualified Type.Alias as Alias
1416
1517-- Pool
1618-- Holds a bunch of variables
@@ -32,7 +34,7 @@ data SolverState = SS {
3234 sSavedEnv :: Env,
3335 sPool :: Pool,
3436 sMark :: Int,
35− sErrors :: [IO P.Doc]
37+ sErrors :: [Alias.Rules -> IO P.Doc]
3638}
3739
3840initialState = SS {
@@ -47,9 +49,19 @@ modifyEnv f = modify $ \state -> state { sEnv = f (sEnv state) }
4749modifyPool f = modify $ \state -> state { sPool = f (sPool state) }
4850
4951addError span message t1 t2 =
50− modify $ \state -> state { sErrors = err : sErrors state }
52+ modify $ \state -> state { sErrors = makeError : sErrors state }
5153 where
52− err = makeError <$> extraPretty t1 <*> extraPretty t2
54+ makeError rules = do
55+ let prettiest = pretty . Alias.realias rules
56+ t1' <- prettiest <$> toSrcType t1
57+ t2' <- prettiest <$> toSrcType t2
58+ return . P.vcat $
59+ [ P.text $ "Type error" ++ location ++ ":"
60+ , P.vcat . map P.text . lines $ if null message then defaultMessage else message
61+ , P.text src
62+ , P.text " Expected Type:" <+> t1'
63+ , P.text " Actual Type:" <+> t2' <> P.text "\n"
64+ ]
5365
5466 location = case span of
5567 NoSpan msg -> ""
@@ -66,13 +78,6 @@ addError span message t1 t2 =
6678
6779 defaultMessage = "Something weird is happening with this value:"
6880
69− makeError pt1 pt2 =
70− P.vcat [ P.text $ "Type error" ++ location ++ ":"
71− , P.vcat . map P.text . lines $ if null message then defaultMessage else message
72− , P.text src
73− , P.text " Expected Type:" <+> pt1
74− , P.text " Actual Type:" <+> pt2 <> P.text "\n"
75− ]
7681
7782switchToPool pool = modifyPool (\_ -> pool)
7883
libraries/Color.elm+9−9
@@ -46,17 +46,17 @@ darkRed = Color 164 0 0 1
4646black = Color 0 0 0 1
4747white = Color 255 255 255 1
4848
49−lightGrey = Color 238 238 236
50−grey = Color 211 215 207
51−darkGrey = Color 186 189 182
49+lightGrey = Color 238 238 236 1
50+grey = Color 211 215 207 1
51+darkGrey = Color 186 189 182 1
5252
53−lightGray = Color 238 238 236
54−gray = Color 211 215 207
55−darkGray = Color 186 189 182
53+lightGray = Color 238 238 236 1
54+gray = Color 211 215 207 1
55+darkGray = Color 186 189 182 1
5656
57−lightCharcoal = Color 136 138 133
58−charcoal = Color 85 87 83
59−darkCharcoal = Color 46 52 54
57+lightCharcoal = Color 136 138 133 1
58+charcoal = Color 85 87 83 1
59+darkCharcoal = Color 46 52 54 1
6060
6161grayscale : Float -> Color
6262grayscale p = hsv 0 0 (1-p)
libraries/Graphics/Collage.elm+1−1
@@ -6,7 +6,7 @@ import List
66import Either (Either, Left, Right)
77import Transform2D (Transform2D, identity)
88import Native.Graphics.Collage
9−import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
9+import Graphics.Element (Element)
1010import Color (Color, black, Gradient)
1111import Maybe (Maybe)
1212import JavaScript (JSString)
libraries/Graphics/Input.elm+1−2
@@ -5,8 +5,7 @@ import Basics (String)
55import Signal (Signal,lift,dropRepeats)
66import Native.Graphics.Input
77import List
8−import Graphics.Element (Element, Three, Pos, ElementPrim, Properties)
9−import Color (Color)
8+import Graphics.Element (Element)
109import Maybe (Maybe)
1110import JavaScript (JSString)
1211