on master help sign in
Use canonical names during type inference
commiteae58a72da7c78bbc2542ca78ccb512adf5da04b authorEvan Czaplicki <info@elm-lang.org> dateWed 28 May 2014, 19:10 (12 years ago) parente2a0b46
3 files changed+97−65
compiler/Type/Environment.hs+46−30 compiler/Type/Type.hs+33−23 compiler/Type/Unify.hs+18−12
compiler/Type/Environment.hs+46−30
@@ -12,21 +12,21 @@ import qualified Data.Map as Map
1212import Data.List (isPrefixOf)
1313import qualified Text.PrettyPrint as PP
1414
15−import AST.Module (ADTs)
1615import qualified AST.Type as T
1716import qualified AST.Variable as V
17+import AST.Module (CanonicalAdt, AdtInfo)
1818import Type.Type
1919
2020type TypeDict = Map.Map String Type
2121type VarDict = Map.Map String Variable
2222
23−data Environment = Environment {
24− constructor :: Map.Map String (IO (Int, [Variable], [Type], Type)),
25− types :: TypeDict,
26− value :: TypeDict
27−}
23+data Environment = Environment
24+ { constructor :: Map.Map String (IO (Int, [Variable], [Type], Type))
25+ , types :: TypeDict
26+ , value :: TypeDict
27+ }
2828
29−initialEnvironment :: ADTs -> IO Environment
29+initialEnvironment :: [CanonicalAdt] -> IO Environment
3030initialEnvironment datatypes = do
3131 types <- makeTypes datatypes
3232 let env = Environment
@@ -36,27 +36,35 @@ initialEnvironment datatypes = do
3636 }
3737 return $ env { constructor = makeConstructors env datatypes }
3838
39−makeTypes :: ADTs -> IO TypeDict
39+makeTypes :: [CanonicalAdt] -> IO TypeDict
4040makeTypes datatypes =
41− do adts <- Traverse.sequence (Map.mapWithKey make datatypes)
42− bs <- Map.fromList . zip (map fst builtins) <$> mapM (uncurry make) builtins
43− return (Map.union adts bs)
41+ do adts <- mapM makeImported datatypes
42+ bs <- mapM makeBuiltin builtins
43+ return (Map.fromList (adts ++ bs))
4444 where
45− make name _ = VarN <$> namedVar Constant name
45+ makeImported :: (V.Canonical, AdtInfo V.Canonical) -> IO (String, Type)
46+ makeImported (var, _) = do
47+ tvar <- namedVar Constant var
48+ return (V.toString var, VarN tvar)
4649
47− tuple n = ("_Tuple" ++ show n, n)
50+ makeBuiltin :: (String, Int) -> IO (String, Type)
51+ makeBuiltin (name, _) = do
52+ name' <- namedVar Constant (V.builtin name)
53+ return (name, VarN name')
4854
49− kind n names = map (\name -> (name, n)) names
50−
51− builtins :: [(String,Int)]
55+ builtins :: [(String, Int)]
5256 builtins = concat [ map tuple [0..9]
5357 , kind 1 ["_List"]
5458 , kind 0 ["Int","Float","Char","String","Bool"]
5559 ]
60+ where
61+ tuple n = ("_Tuple" ++ show n, n)
62+ kind n names = map (\name -> (name, n)) names
63+
5664
5765
5866makeConstructors :: Environment
59− -> ADTs
67+ -> [CanonicalAdt]
6068 -> Map.Map String (IO (Int, [Variable], [Type], Type))
6169makeConstructors env datatypes = Map.fromList builtins
6270 where
@@ -76,30 +84,32 @@ makeConstructors env datatypes = Map.fromList builtins
7684 builtins = [ ("[]", inst 1 $ \ [t] -> ([], list t))
7785 , ("::", inst 1 $ \ [t] -> ([t, list t], list t))
7886 ] ++ map tupleCtor [0..9]
79− ++ concatMap (ctorToType env) (Map.toList datatypes)
87+ ++ concatMap (ctorToType env) datatypes
8088
8189
82−--ctorToType :: Environment -> ADT -> [ (String, IO (Int, [Variable], [Type], Type)) ]
90+ctorToType :: Environment
91+ -> (V.Canonical, AdtInfo V.Canonical)
92+ -> [(String, IO (Int, [Variable], [Type], Type))]
8393ctorToType env (name, (tvars, ctors)) =
84− zip (map fst ctors) (map inst ctors)
94+ zip (map (V.toString . fst) ctors) (map inst ctors)
8595 where
86− inst :: (String, [T.CanonicalType]) -> IO (Int, [Variable], [Type], Type)
96+ inst :: (V.Canonical, [T.CanonicalType]) -> IO (Int, [Variable], [Type], Type)
8797 inst ctor = do
8898 ((args, tipe), dict) <- State.runStateT (go ctor) Map.empty
8999 return (length args, Map.elems dict, args, tipe)
90100
91101
92− go :: (String, [T.CanonicalType]) -> State.StateT VarDict IO ([Type], Type)
102+ go :: (V.Canonical, [T.CanonicalType]) -> State.StateT VarDict IO ([Type], Type)
93103 go (_, args) = do
94104 types <- mapM (instantiator env) args
95− returnType <- instantiator env (T.Data (error "name") (map T.Var tvars))
105+ returnType <- instantiator env (T.App (T.Type name) (map T.Var tvars))
96106 return (types, returnType)
97107
98108
99109get :: Environment -> (Environment -> Map.Map String a) -> String -> a
100110get env subDict key = Map.findWithDefault err key (subDict env)
101111 where
102− err = error $ "\nCould not find type constructor '" ++ key ++ "' while checking types."
112+ err = error $ "Could not find type constructor '" ++ key ++ "' while checking types."
103113
104114
105115freshDataScheme :: Environment -> String -> IO (Int, [Variable], [Type], Type)
@@ -128,7 +138,7 @@ instantiator env sourceType = go sourceType
128138 case Map.lookup x dict of
129139 Just v -> return (VarN v)
130140 Nothing ->
131− do var <- State.liftIO $ namedVar flex x
141+ do var <- State.liftIO $ namedVar flex (V.local x)
132142 State.put (Map.insert x var dict)
133143 return (VarN var)
134144 where
@@ -137,12 +147,18 @@ instantiator env sourceType = go sourceType
137147 | "appendable" `isPrefixOf` x = Is Appendable
138148 | otherwise = Flexible
139149
140− T.Data name ts -> do
150+ T.Aliased _ t -> go t
151+
152+ T.Type var ->
153+ case Map.lookup (V.toString var) (types env) of
154+ Just t -> return t
155+ Nothing -> error $ "Could not find type constructor '" ++
156+ V.toString var ++ "' while checking types."
157+
158+ T.App t ts -> do
159+ t' <- go t
141160 ts' <- mapM go ts
142− case Map.lookup (V.toString name) (types env) of
143− Just t -> return $ foldl (<|) t ts'
144− Nothing -> error $ "\nCould not find type constructor '" ++
145− V.toString name ++ "' while checking types."
161+ return $ foldl (<|) t' ts'
146162
147163 T.Record fields ext -> do
148164 fields' <- Traverse.traverse (mapM go) (T.fieldMap fields)
compiler/Type/Type.hs+33−23
@@ -1,3 +1,4 @@
1+{-# OPTIONS_GHC -W #-}
12module Type.Type where
23
34import qualified Data.Char as Char
@@ -12,7 +13,6 @@ import Control.Monad.State
1213import Control.Monad.Error
1314import Data.Traversable (traverse)
1415import AST.Annotation
15−import AST.Helpers (isTuple)
1616import qualified AST.Type as T
1717import qualified AST.Variable as Var
1818
@@ -36,7 +36,7 @@ type Type = TermN Variable
3636type Variable = UF.Point Descriptor
3737
3838type SchemeName = String
39−type TypeName = String
39+type TypeName = Var.Canonical
4040
4141type Constraint a b = Located (BasicConstraint a b)
4242data BasicConstraint a b
@@ -96,7 +96,7 @@ data Flex = Rigid | Flexible | Constant | Is SuperType
9696data SuperType = Number | Comparable | Appendable
9797 deriving (Show, Eq)
9898
99−namedVar :: Flex -> String -> IO Variable
99+namedVar :: Flex -> Var.Canonical -> IO Variable
100100namedVar flex name = UF.fresh $ Descriptor {
101101 structure = Nothing,
102102 rank = noRank,
@@ -203,8 +203,12 @@ instance PrettyType Descriptor where
203203 pretty when desc =
204204 case (structure desc, name desc) of
205205 (Just term, _) -> pretty when term
206− (_, Just name) -> if not (isTuple name) then P.text name else
207− P.parens . P.text $ replicate (read (drop 6 name) - 1) ','
206+ (_, Just name)
207+ | Var.isTuple name ->
208+ P.parens . P.text $ replicate (read (drop 6 (Var.toString name)) - 1) ','
209+ | otherwise ->
210+ P.text (Var.toString name)
211+
208212 _ -> P.text "?"
209213
210214
@@ -278,23 +282,20 @@ addNames value = do
278282 getNames desc state@(vars, a, b, c) =
279283 let name' = name desc in
280284 case name' of
281− Just var -> (name', (var:vars, a, b, c))
282− Nothing -> (name', state)
285+ Just (Var.Canonical _ var) -> (name', (var:vars, a, b, c))
286+ _ -> (name', state)
283287
284288 rename desc state@(vars, a, b, c) =
285289 case name desc of
286290 Just var -> (Just var, state)
287291 Nothing ->
288292 case flex desc of
289− Is Number -> (Just $ "number" ++ replicate a '\'', (vars, a+1, b, c))
290− Is Comparable -> (Just $ "comparable" ++ replicate b '\'', (vars, a, b+1, c))
291− Is Appendable -> (Just $ "appendable" ++ replicate c '\'', (vars, a, b, c+1))
292− other -> (Just $ head vars, (tail vars, a, b, c))
293− where mark = case other of
294− Flexible -> ""
295− Rigid -> "!"
296− Constant -> "#"
297−
293+ Is Number -> (local $ "number" ++ replicate a '\'', (vars, a+1, b, c))
294+ Is Comparable -> (local $ "comparable" ++ replicate b '\'', (vars, a, b+1, c))
295+ Is Appendable -> (local $ "appendable" ++ replicate c '\'', (vars, a, b, c+1))
296+ _ -> (local $ head vars, (tail vars, a, b, c))
297+ where
298+ local v = Just (Var.local v)
298299
299300type CrawlState = ([String], Int, Int, Int)
300301
@@ -367,24 +368,33 @@ toSrcType variable = do
367368 Just term ->
368369 case term of
369370 App1 a b -> do
370− T.Data name ts <- toSrcType a
371+ a' <- toSrcType a
371372 b' <- toSrcType b
372− return (T.Data name (ts ++ [b']))
373+ case a' of
374+ T.App f args -> return $ T.App f (args ++ [b'])
375+ _ -> return $ T.App a' [b']
376+
373377 Fun1 a b -> T.Lambda <$> toSrcType a <*> toSrcType b
378+
374379 Var1 a -> toSrcType a
380+
375381 EmptyRecord1 -> return $ T.Record [] Nothing
382+
376383 Record1 tfields extension -> do
377384 fields' <- traverse (mapM toSrcType) tfields
378385 let fields = concat [ map ((,) name) ts | (name,ts) <- Map.toList fields' ]
379386 ext' <- toSrcType extension
380387 return $ case ext' of
381388 T.Record fs ext -> T.Record (fs ++ fields) ext
382− T.Var x -> T.Record fields (Just ext')
389+ T.Var _ -> T.Record fields (Just ext')
383390 _ -> error "Used toSrcType on a type that is not well-formed"
391+
384392 Nothing ->
385393 case name desc of
386− Just x@(c:_) | Char.isLower c -> return (T.Var x)
387− | otherwise -> return (T.Data (Var.Canonical (error "did not finish converting toSrcType") x) [])
394+ Just var@(Var.Canonical _ x@(c:_))
395+ | Char.isLower c -> return (T.Var x)
396+ | otherwise -> return $ T.Type var
397+
388398 _ -> error $ concat
389399 [ "Problem converting the following type "
390400 , "from a type-checker type to a source-syntax type:"
@@ -399,10 +409,10 @@ collectApps variable = go [] variable
399409 desc <- UF.descriptor variable
400410 case (structure desc, vars) of
401411 (Nothing, [v]) -> case name desc of
402− Just "_List" -> return (List v)
412+ Just n | Var.isList n -> return (List v)
403413 _ -> return Other
404414 (Nothing, vs) -> case name desc of
405− Just ctor | isTuple ctor -> return (Tuple vs)
415+ Just n | Var.isTuple n -> return (Tuple vs)
406416 _ -> return Other
407417 (Just term, _) -> case term of
408418 App1 a b -> go (vars ++ [b]) a
compiler/Type/Unify.hs+18−12
@@ -2,10 +2,12 @@
22module Type.Unify (unify) where
33
44import Control.Monad.State
5+import qualified Data.List as List
56import qualified Data.Map as Map
67import qualified Data.Maybe as Maybe
78import qualified Data.UnionFind.IO as UF
89import qualified AST.Annotation as A
10+import qualified AST.Variable as Var
911import qualified Type.State as TS
1012import Type.Type
1113import Type.PrettyPrint
@@ -23,7 +25,7 @@ actuallyUnify region variable1 variable2 = do
2325 desc2 <- liftIO $ UF.descriptor variable2
2426 let unify' = unify region
2527
26− name' :: Maybe String
28+ name' :: Maybe Var.Canonical
2729 name' = case (name desc1, name desc2) of
2830 (Just name1, Just name2) ->
2931 case (flex desc1, flex desc2) of
@@ -77,10 +79,12 @@ actuallyUnify region variable1 variable2 = do
7779 liftIO $ UF.modifyDescriptor var $ \desc -> desc { flex = Flexible }
7880 unify' variable1 variable2
7981
80− unifyNumber svar name
81− | name `elem` ["Int","Float","number"] = flexAndUnify svar
82− | otherwise = TS.addError region (Just hint) variable1 variable2
83− where hint = "A number must be an Int or Float."
82+ unifyNumber svar (Var.Canonical home name) =
83+ case home of
84+ Var.BuiltIn | name `elem` ["Int","Float"] -> flexAndUnify svar
85+ Var.Local | List.isPrefixOf "number" name -> flexAndUnify svar
86+ _ -> let hint = "A number must be an Int or Float."
87+ in TS.addError region (Just hint) variable1 variable2
8488
8589 comparableError maybe =
8690 TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
@@ -90,9 +94,11 @@ actuallyUnify region variable1 variable2 = do
9094 TS.addError region (Just $ Maybe.fromMaybe msg maybe) variable1 variable2
9195 where msg = "An appendable must be of type String, List, or Text."
9296
93− unifyComparable var name
94− | name `elem` ["Int","Float","Char","String","comparable"] = flexAndUnify var
95− | otherwise = comparableError Nothing
97+ unifyComparable var (Var.Canonical home name) =
98+ case home of
99+ Var.BuiltIn | name `elem` ["Int","Float","Char","String"] -> flexAndUnify var
100+ Var.Local | List.isPrefixOf "comparable" name -> flexAndUnify var
101+ _ -> comparableError Nothing
96102
97103 unifyComparableStructure varSuper varFlex =
98104 do struct <- liftIO $ collectApps varFlex
@@ -136,10 +142,10 @@ actuallyUnify region variable1 variable2 = do
136142 (Is Comparable, _, _, _) -> unifyComparableStructure variable1 variable2
137143 (_, Is Comparable, _, _) -> unifyComparableStructure variable2 variable1
138144
139− (Is Appendable, _, _, Just ctor)
140− | ctor `elem` ["Text.Text","String"] -> flexAndUnify variable1
141− (_, Is Appendable, Just ctor, _)
142− | ctor `elem` ["Text.Text","String"] -> flexAndUnify variable2
145+ (Is Appendable, _, _, Just name)
146+ | Var.isText name || Var.isPrim "String" name -> flexAndUnify variable1
147+ (_, Is Appendable, Just name, _)
148+ | Var.isText name || Var.isPrim "String" name -> flexAndUnify variable2
143149 (Is Appendable, _, _, _) -> unifyAppendable variable1 variable2
144150 (_, Is Appendable, _, _) -> unifyAppendable variable2 variable1
145151