on master help sign in
Get public types working again
commit22736cfa699e4a47fe5510398564cc9e4ca5fa58 authorEvan Czaplicki <evancz@users.noreply.github.com> dateMon 11 Dec 2017, 14:11 (9 years ago) parent4eaeee5
2 files changed+255−182
src/Elm/Compiler/Type.hs+80−91 src/Elm/Compiler/Type/Extract.hs+175−91
src/Elm/Compiler/Type.hs+80−91
@@ -5,24 +5,24 @@ module Elm.Compiler.Type
55 , Format(..)
66 , toString
77 , Program(..)
8+ , Alias(..)
9+ , Union(..)
810 , encode
911 , decoder
1012 , encodeProgram
1113 )
1214 where
1315
14−import Control.Arrow ((***))
15−import Data.Aeson ((.:))
16−import qualified Data.Aeson as Aeson
17−import qualified Data.Text as Text
16+
1817import Data.Text (Text)
18+import qualified Data.Text as Text
19+import qualified Data.Text.Encoding as Text
1920import qualified Text.PrettyPrint as P
2021import Text.PrettyPrint ((<+>))
2122
22−import qualified AST.Helpers as Help
23−import qualified AST.Type as Type
24−import qualified AST.Variable as Var
25−import qualified Parse.Helpers as Parse
23+import qualified AST.Source as Src
24+import qualified Elm.Name as N
25+import qualified Parse.Primitives as Parse
2626import qualified Parse.Type as Type
2727import qualified Reporting.Annotation as A
2828import qualified Json.Decode as Decode
@@ -36,19 +36,25 @@ import Json.Encode ((==>))
3636
3737data Type
3838 = Lambda Type Type
39− | Var Text
40− | Type Text [Type]
41− | Record [(Text, Type)] (Maybe Type)
39+ | Var N.Name
40+ | Type N.Name [Type]
41+ | Record [(N.Name, Type)] (Maybe Type)
42+ | Unit
43+ | Tuple Type Type [Type]
4244
4345
4446data Program =
4547 Program
4648 { _message :: Type
47− , _aliases :: [( Text, [Text], Type )]
48− , _unions :: [( Text, [Text], [(Text, [Type])] )]
49+ , _aliases :: [Alias]
50+ , _unions :: [Union]
4951 }
5052
5153
54+data Alias = Alias N.Name [N.Name] Type
55+data Union = Union N.Name [N.Name] [(N.Name, [Type])]
56+
57+
5258
5359-- TO STRING
5460
@@ -89,30 +95,38 @@ toDoc context tipe =
8995 Var name ->
9096 P.text (Text.unpack name)
9197
92− Type name [] ->
93− P.text (if name == Help.zeroTuple then "()" else Text.unpack name)
94−
95− Type name arguments@(arg:args) ->
96− if Help.isTuple name then
97− P.sep
98− [ P.cat ("(" <+> toDoc None arg : map (\a -> "," <+> toDoc None a) args)
99− , ")"
100− ]
101−
102− else
103− let
104− application =
105− P.hang
106− (P.text (Text.unpack name))
107− 2
108− (P.sep $ map (toDoc InType) arguments)
109− in
110− case context of
111− InType ->
112− P.parens application
98+ Unit ->
99+ "()"
100+
101+ Tuple a b cs ->
102+ P.sep
103+ [ P.cat $
104+ [ "(" <+> toDoc None a
105+ , "," <+> toDoc None b
106+ ]
107+ ++ map ("," <+>) (map (toDoc None) cs)
108+ , ")"
109+ ]
110+
111+ Type name args ->
112+ case args of
113+ [] ->
114+ P.text (Text.unpack name)
115+
116+ _ ->
117+ let
118+ application =
119+ P.hang
120+ (P.text (Text.unpack name))
121+ 2
122+ (P.sep $ map (toDoc InType) args)
123+ in
124+ case context of
125+ InType ->
126+ P.parens application
113127
114− _ ->
115− application
128+ _ ->
129+ application
116130
117131 Record _ _ ->
118132 case flattenRecord tipe of
@@ -175,66 +189,41 @@ encode tipe =
175189
176190decoder :: Decode.Decoder Type
177191decoder =
178− Decode.oneOf
179− [
180− do txt <- Decode.text
181− case Parse.run Type.expression (Text.replace "'" "_" txt) of
182− Left _ ->
183− Decode.fail "Expecting a type, like (String -> Int)"
184−
185− Right (tipe, _, _) ->
186− Decode.succeed (fromRawType tipe)
187− ,
188− Decode.aeson
189− ]
190−
192+ do txt <- Decode.text
193+ case Parse.run Type.expression (Text.encodeUtf8 (Text.replace "'" "_" txt)) of
194+ Left _ ->
195+ Decode.fail "Expecting a type, like (String -> Int)"
191196
192−instance Aeson.FromJSON Type where
193− parseJSON =
194− Aeson.withObject "Type" $ \object ->
195− do tag <- object .: "tag"
196− case (tag :: String) of
197− "lambda" ->
198− Lambda <$> object .: "in" <*> object .: "out"
197+ Right (tipe, _, _) ->
198+ Decode.succeed (fromRawType tipe)
199199
200− "var" ->
201− Var <$> object .: "name"
202200
203− "type" ->
204− do name <- object .: "name"
205− return (Type name [])
206−
207− "app" ->
208− do func <- object .: "func"
209− args <- object .: "args"
210− case func of
211− Type name [] ->
212− return (Type name args)
213−
214− _ ->
215− fail "unexpected type application"
216−
217− "record" ->
218− Record <$> object .: "fields" <*> object .: "extension"
219−
220− _ ->
221− fail $ "Error when decoding type with tag: " ++ tag
222−
223−
224−fromRawType :: Type.Raw -> Type
225−fromRawType (A.A _ astType) =
201+fromRawType :: Src.Type -> Type
202+fromRawType (A.At _ astType) =
226203 case astType of
227− Type.RLambda t1 t2 ->
204+ Src.TLambda t1 t2 ->
228205 Lambda (fromRawType t1) (fromRawType t2)
229206
230− Type.RVar x ->
207+ Src.TVar x ->
231208 Var x
232209
233− Type.RType (A.A _ name) args ->
234− Type (Var.rawToText name) (map fromRawType args)
210+ Src.TUnit ->
211+ Unit
212+
213+ Src.TTuple a b cs ->
214+ Tuple
215+ (fromRawType a)
216+ (fromRawType b)
217+ (map fromRawType cs)
218+
219+ Src.TType _ _ name args ->
220+ Type name (map fromRawType args)
235221
236− Type.RRecord fields ext ->
237− Record (map (A.drop *** fromRawType) fields) (fmap fromRawType ext)
222+ Src.TRecord fields ext ->
223+ let fromField (A.At _ field, tipe) = (field, fromRawType tipe) in
224+ Record
225+ (map fromField fields)
226+ (fmap fromRawType ext)
238227
239228
240229
@@ -250,8 +239,8 @@ encodeProgram (Program msg aliases unions) =
250239 ]
251240
252241
253−toAliasField :: ( Text, [Text], Type ) -> ( String, Encode.Value )
254−toAliasField ( name, args, tipe ) =
242+toAliasField :: Alias -> ( String, Encode.Value )
243+toAliasField (Alias name args tipe) =
255244 Text.unpack name ==>
256245 Encode.object
257246 [ "args" ==> Encode.list Encode.text args
@@ -259,8 +248,8 @@ toAliasField ( name, args, tipe ) =
259248 ]
260249
261250
262−toUnionField :: ( Text, [Text], [(Text, [Type])] ) -> ( String, Encode.Value )
263−toUnionField ( name, args, constructors ) =
251+toUnionField :: Union -> ( String, Encode.Value )
252+toUnionField (Union name args constructors) =
264253 Text.unpack name ==>
265254 Encode.object
266255 [ "args" ==> Encode.list Encode.text args
src/Elm/Compiler/Type/Extract.hs+175−91
@@ -1,158 +1,242 @@
11{-# OPTIONS_GHC -Wall #-}
22{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE Rank2Types #-}
34module Elm.Compiler.Type.Extract
4− ( extract
5− , extractProgram
5+ ( fromAnnotation
6+ , fromType
7+ , fromProgram
68 )
79 where
810
9−import qualified Control.Monad.Writer.Strict as Writer
11+
12+import Data.Map ((!))
1013import qualified Data.Map as Map
1114import qualified Data.Maybe as Maybe
15+import Data.Monoid ((<>))
1216import qualified Data.Set as Set
13−import Data.Text (Text)
1417
15−import qualified AST.Module as Module
18+import qualified AST.Canonical as Can
19+import qualified AST.Optimized as Opt
1620import qualified AST.Module.Name as ModuleName
17−import qualified AST.Type as T
18−import qualified AST.Variable as Var
19−import Elm.Compiler.Type (Type(..), Program(Program))
21+import qualified AST.Utils.Type as Type
22+import qualified Elm.Compiler.Type as T
23+import qualified Elm.Interface as I
24+import qualified Elm.Name as N
2025
2126
2227
2328-- EXTRACTION
2429
2530
26−extract :: T.Canonical -> Type
27−extract astType =
28− fst $ Writer.runWriter $ extractHelp astType
31+fromAnnotation :: Can.Annotation -> T.Type
32+fromAnnotation (Can.Forall _ astType) =
33+ fromType astType
2934
3035
31−type Deps =
32− ( Set.Set Var.Canonical -- aliases
33− , Set.Set Var.Canonical -- unions
34− )
36+fromType :: Can.Type -> T.Type
37+fromType astType =
38+ snd (run (extract astType))
3539
3640
37−diff :: Deps -> Deps -> Deps
38−diff (oldAliases, oldUnions) (newAliases, newUnions) =
39− ( Set.difference newAliases oldAliases
40− , Set.difference newUnions oldUnions
41− )
41+extract :: Can.Type -> Extractor T.Type
42+extract astType =
43+ case astType of
44+ Can.TLambda arg result ->
45+ T.Lambda
46+ <$> extract arg
47+ <*> extract result
4248
49+ Can.TVar x ->
50+ pure (T.Var x)
4351
44−extractHelp :: T.Canonical -> Writer.Writer Deps Type
45−extractHelp astType =
46− case astType of
47− T.Lambda arg result ->
48− Lambda <$> extractHelp arg <*> extractHelp result
52+ Can.TType home name args ->
53+ addUnion (Opt.Global home name) (T.Type (toPublicName home name))
54+ <*> traverse extract args
55+
56+ Can.TRecord fields ext ->
57+ T.Record
58+ <$> fmap Map.toList (traverse extract fields)
59+ <*> traverse extract ext
4960
50− T.Var x ->
51− return (Var x)
61+ Can.TUnit ->
62+ pure T.Unit
5263
53− T.Type var args ->
54− do Writer.tell ( Set.empty, Set.singleton var )
55− Type (Var.toText var) <$> traverse extractHelp args
64+ Can.TTuple a b maybeC ->
65+ T.Tuple
66+ <$> extract a
67+ <*> extract b
68+ <*> traverse extract (Maybe.maybeToList maybeC)
5669
57− T.Record fields ext ->
58− Record
59− <$> traverse (traverse extractHelp) fields
60− <*> traverse extractHelp ext
70+ Can.TAlias home name args aliasType ->
71+ do addAlias (Opt.Global home name) ()
72+ _ <- extract (Type.dealias args aliasType)
73+ T.Type (toPublicName home name)
74+ <$> traverse (extract . snd) args
6175
62− T.Aliased name args aliasedType ->
63− do Writer.tell ( Set.singleton name, Set.empty )
64− _ <- extractHelp (T.dealias args aliasedType)
65− Type (Var.toText name) <$> traverse (extractHelp . snd) args
76+
77+toPublicName :: ModuleName.Canonical -> N.Name -> N.Name
78+toPublicName (ModuleName.Canonical _ home) name =
79+ home <> "." <> name
6680
6781
6882
6983-- EXTRACT MODEL, MSG, AND ANY TRANSITIVE DEPENDENCIES
7084
7185
72−extractProgram :: Module.Interfaces -> ModuleName.Canonical -> Maybe Program
73−extractProgram interfaces name =
86+fromProgram :: I.Interfaces -> ModuleName.Canonical -> Maybe T.Program
87+fromProgram interfaces name =
7488 do iface <- Map.lookup name interfaces
75− mainType <- Map.lookup "main" (Module.iTypes iface)
76−
77− message <-
78− case T.deepDealias mainType of
79− T.Type _program [_flags, _model, msg] -> Just msg
80− T.Type _node [msg] -> Just msg
81− _ -> Nothing
89+ mainType <- Map.lookup "main" (I._types iface)
90+ message <- getMessage mainType
8291
83− let (msgType, msgDeps) = Writer.runWriter (extractHelp message)
84− let (aliases, unions) = extractTransitive interfaces mempty msgDeps
85− Just (Program msgType aliases unions)
92+ let (msgDeps, msgType) = run (extract message)
93+ let (aliases, unions) = extractTransitive interfaces noDeps msgDeps
94+ Just (T.Program msgType aliases unions)
8695
8796
88−type Alias =
89− ( Text, [Text], Type )
97+getMessage :: Can.Annotation -> Maybe Can.Type
98+getMessage (Can.Forall _ mainType) =
99+ case Type.deepDealias mainType of
100+ Can.TType _ _program [_flags, _model, msg] ->
101+ Just msg
90102
103+ Can.TType _ _node [msg] ->
104+ Just msg
91105
92−type Union =
93− ( Text, [Text], [(Text, [Type])] )
106+ _ ->
107+ Nothing
94108
95109
96−extractTransitive :: Module.Interfaces -> Deps -> Deps -> ( [Alias], [Union] )
97−extractTransitive interfaces oldDeps currentDeps =
110+extractTransitive :: I.Interfaces -> Deps -> Deps -> ( [T.Alias], [T.Union] )
111+extractTransitive interfaces (Deps seenAliases seenUnions) (Deps nextAliases nextUnions) =
98112 let
99− (aliases, unions) =
100− diff oldDeps currentDeps
113+ aliases = Set.difference nextAliases seenAliases
114+ unions = Set.difference nextUnions seenUnions
101115 in
102116 if Set.null aliases && Set.null unions then
103117 ( [], [] )
104118
105119 else
106120 let
107− (result, newDeps) =
108− Writer.runWriter $ do
109− publicAliases <- mapM (extractAlias interfaces) (Set.toList aliases)
110− publicUnions <- mapM (extractUnion interfaces) (Set.toList unions)
111− return ( Maybe.catMaybes publicAliases, Maybe.catMaybes publicUnions )
121+ (newDeps, result) =
122+ run $
123+ (,)
124+ <$> traverse (extractAlias interfaces) (Set.toList aliases)
125+ <*> traverse (extractUnion interfaces) (Set.toList unions)
126+
127+ oldDeps =
128+ Deps (Set.union seenAliases nextAliases) (Set.union seenUnions nextUnions)
112129
113130 remainingResult =
114− extractTransitive interfaces (mappend oldDeps currentDeps) newDeps
131+ extractTransitive interfaces oldDeps newDeps
115132 in
116133 mappend result remainingResult
117134
118135
119−extractAlias :: Module.Interfaces -> Var.Canonical -> Writer.Writer Deps (Maybe Alias)
120−extractAlias interfaces var =
136+extractAlias :: I.Interfaces -> Opt.Global -> Extractor T.Alias
137+extractAlias interfaces (Opt.Global home name) =
121138 let
122− toAlias (args, tipe) =
123− (,,) (Var.toText var) args <$> extractHelp tipe
139+ (I.Interface _ _ aliases _) = interfaces ! home
140+ (Can.Alias args aliasType _) = aliases ! name
124141 in
125− traverse toAlias (get Module.iAliases interfaces var)
142+ T.Alias (toPublicName home name) args <$> extract aliasType
126143
127144
128−extractUnion :: Module.Interfaces -> Var.Canonical -> Writer.Writer Deps (Maybe Union)
129−extractUnion interfaces var =
145+extractUnion :: I.Interfaces -> Opt.Global -> Extractor T.Union
146+extractUnion interfaces (Opt.Global home name) =
130147 let
131− toUnion (args, constructors) =
132− (,,) (Var.toText var) args
133− <$> traverse (traverse (traverse extractHelp)) constructors
148+ (I.Interface _ unions _ _) = interfaces ! home
149+ (Can.Union args constructors) = unions ! name
134150 in
135− traverse toUnion (get Module.iUnions interfaces var)
151+ T.Union (toPublicName home name) args
152+ <$> traverse (traverse (traverse extract)) constructors
136153
137154
138−get :: (Module.Interface -> Map.Map Text a) -> Module.Interfaces -> Var.Canonical -> Maybe a
139−get getInfo interfaces var =
140− do (home, name) <- getHome var
141− iface <- Map.lookup home interfaces
142− Map.lookup name (getInfo iface)
143155
156+-- DEPS
157+
158+
159+data Deps =
160+ Deps
161+ { _aliases :: Set.Set Opt.Global
162+ , _unions :: Set.Set Opt.Global
163+ }
144164
145−getHome :: Var.Canonical -> Maybe (ModuleName.Canonical, Text)
146−getHome (Var.Canonical home name) =
147− case home of
148− Var.BuiltIn ->
149− Nothing
150165
151− Var.Module moduleName ->
152− Just (moduleName, name)
166+{-# NOINLINE noDeps #-}
167+noDeps :: Deps
168+noDeps =
169+ Deps Set.empty Set.empty
153170
154− Var.TopLevel moduleName ->
155− Just (moduleName, name)
156171
157− Var.Local ->
158− Nothing
172+
173+-- EXTRACTOR
174+
175+
176+newtype Extractor a =
177+ Extractor (
178+ forall result.
179+ Set.Set Opt.Global
180+ -> Set.Set Opt.Global
181+ -> (Set.Set Opt.Global -> Set.Set Opt.Global -> a -> result)
182+ -> result
183+ )
184+
185+
186+run :: Extractor a -> (Deps, a)
187+run (Extractor k) =
188+ k Set.empty Set.empty $ \aliases unions value ->
189+ ( Deps aliases unions, value )
190+
191+
192+addAlias :: Opt.Global -> a -> Extractor a
193+addAlias alias value =
194+ Extractor $ \aliases unions ok ->
195+ ok (Set.insert alias aliases) unions value
196+
197+
198+addUnion :: Opt.Global -> a -> Extractor a
199+addUnion union value =
200+ Extractor $ \aliases unions ok ->
201+ ok aliases (Set.insert union unions) value
202+
203+
204+instance Functor Extractor where
205+ fmap func (Extractor k) =
206+ Extractor $ \aliases unions ok ->
207+ let
208+ ok1 a1 u1 value =
209+ ok a1 u1 (func value)
210+ in
211+ k aliases unions ok1
212+
213+
214+instance Applicative Extractor where
215+ pure value =
216+ Extractor $ \aliases unions ok ->
217+ ok aliases unions value
218+
219+ (<*>) (Extractor kf) (Extractor kv) =
220+ Extractor $ \aliases unions ok ->
221+ let
222+ ok1 a1 u1 func =
223+ let
224+ ok2 a2 u2 value =
225+ ok a2 u2 (func value)
226+ in
227+ kv a1 u1 ok2
228+ in
229+ kf aliases unions ok1
230+
231+
232+instance Monad Extractor where
233+ return = pure
234+
235+ (>>=) (Extractor ka) callback =
236+ Extractor $ \aliases unions ok ->
237+ let
238+ ok1 a1 u1 value =
239+ case callback value of
240+ Extractor kb -> kb a1 u1 ok
241+ in
242+ ka aliases unions ok1