1module Language.PureScript.Environment where
2
3import Prelude.Compat
4import Protolude (ordNub)
5
6import GHC.Generics (Generic)
7import Control.DeepSeq (NFData)
8import Codec.Serialise (Serialise)
9import Data.Aeson ((.=), (.:))
10import qualified Data.Aeson as A
11import qualified Data.Map as M
12import qualified Data.Set as S
13import Data.Maybe (fromMaybe, mapMaybe)
14import Data.Text (Text)
15import qualified Data.Text as T
16import Data.Tree (Tree, rootLabel)
17import qualified Data.Graph as G
18import Data.Foldable (toList)
19import qualified Data.List.NonEmpty as NEL
20
21import Language.PureScript.AST.SourcePos
22import Language.PureScript.Crash
23import Language.PureScript.Names
24import Language.PureScript.Roles
25import Language.PureScript.TypeClassDictionaries
26import Language.PureScript.Types
27import qualified Language.PureScript.Constants.Prim as C
28
29-- | The @Environment@ defines all values and types which are currently in scope:
30data Environment = Environment
31  { names :: M.Map (Qualified Ident) (SourceType, NameKind, NameVisibility)
32  -- ^ Values currently in scope
33  , types :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
34  -- ^ Type names currently in scope
35  , dataConstructors :: M.Map (Qualified (ProperName 'ConstructorName)) (DataDeclType, ProperName 'TypeName, SourceType, [Ident])
36  -- ^ Data constructors currently in scope, along with their associated type
37  -- constructor name, argument types and return type.
38  , roleDeclarations :: M.Map (Qualified (ProperName 'TypeName)) [Role]
39  -- ^ Explicit role declarations currently in scope. Note that this field is
40  -- only used to store declared roles temporarily until they can be checked;
41  -- to find a type's real checked and/or inferred roles, refer to the TypeKind
42  -- in the `types` field.
43  , typeSynonyms :: M.Map (Qualified (ProperName 'TypeName)) ([(Text, Maybe SourceType)], SourceType)
44  -- ^ Type synonyms currently in scope
45  , typeClassDictionaries :: M.Map (Maybe ModuleName) (M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) (NEL.NonEmpty NamedDict)))
46  -- ^ Available type class dictionaries. When looking up 'Nothing' in the
47  -- outer map, this returns the map of type class dictionaries in local
48  -- scope (ie dictionaries brought in by a constrained type).
49  , typeClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
50  -- ^ Type classes
51  } deriving (Show, Generic)
52
53instance NFData Environment
54
55-- | Information about a type class
56data TypeClassData = TypeClassData
57  { typeClassArguments :: [(Text, Maybe SourceType)]
58  -- ^ A list of type argument names, and their kinds, where kind annotations
59  -- were provided.
60  , typeClassMembers :: [(Ident, SourceType)]
61  -- ^ A list of type class members and their types. Type arguments listed above
62  -- are considered bound in these types.
63  , typeClassSuperclasses :: [SourceConstraint]
64  -- ^ A list of superclasses of this type class. Type arguments listed above
65  -- are considered bound in the types appearing in these constraints.
66  , typeClassDependencies :: [FunctionalDependency]
67  -- ^ A list of functional dependencies for the type arguments of this class.
68  , typeClassDeterminedArguments :: S.Set Int
69  -- ^ A set of indexes of type argument that are fully determined by other
70  -- arguments via functional dependencies. This can be computed from both
71  -- typeClassArguments and typeClassDependencies.
72  , typeClassCoveringSets :: S.Set (S.Set Int)
73  -- ^ A sets of arguments that can be used to infer all other arguments.
74  , typeClassIsEmpty :: Bool
75  -- ^ Whether or not dictionaries for this type class are necessarily empty.
76  } deriving (Show, Generic)
77
78instance NFData TypeClassData
79
80-- | A functional dependency indicates a relationship between two sets of
81-- type arguments in a class declaration.
82data FunctionalDependency = FunctionalDependency
83  { fdDeterminers :: [Int]
84  -- ^ the type arguments which determine the determined type arguments
85  , fdDetermined  :: [Int]
86  -- ^ the determined type arguments
87  } deriving (Show, Generic)
88
89instance NFData FunctionalDependency
90instance Serialise FunctionalDependency
91
92instance A.FromJSON FunctionalDependency where
93  parseJSON = A.withObject "FunctionalDependency" $ \o ->
94    FunctionalDependency
95      <$> o .: "determiners"
96      <*> o .: "determined"
97
98instance A.ToJSON FunctionalDependency where
99  toJSON FunctionalDependency{..} =
100    A.object [ "determiners" .= fdDeterminers
101             , "determined" .= fdDetermined
102             ]
103
104-- | The initial environment with no values and only the default javascript types defined
105initEnvironment :: Environment
106initEnvironment = Environment M.empty allPrimTypes M.empty M.empty M.empty M.empty allPrimClasses
107
108-- | A constructor for TypeClassData that computes which type class arguments are fully determined
109-- and argument covering sets.
110-- Fully determined means that this argument cannot be used when selecting a type class instance.
111-- A covering set is a minimal collection of arguments that can be used to find an instance and
112-- therefore determine all other type arguments.
113--
114-- An example of the difference between determined and fully determined would be with the class:
115-- ```class C a b c | a -> b, b -> a, b -> c```
116-- In this case, `a` must differ when `b` differs, and vice versa - each is determined by the other.
117-- Both `a` and `b` can be used in selecting a type class instance. However, `c` cannot - it is
118-- fully determined by `a` and `b`.
119--
120-- Define a graph of type class arguments with edges being fundep determiners to determined. Each
121-- argument also has a self looping edge.
122-- An argument is fully determined if doesn't appear at the start of a path of strongly connected components.
123-- An argument is not fully determined otherwise.
124--
125-- The way we compute this is by saying: an argument X is fully determined if there are arguments that
126-- determine X that X does not determine. This is the same thing: everything X determines includes everything
127-- in its SCC, and everything determining X is either before it in an SCC path, or in the same SCC.
128makeTypeClassData
129  :: [(Text, Maybe SourceType)]
130  -> [(Ident, SourceType)]
131  -> [SourceConstraint]
132  -> [FunctionalDependency]
133  -> Bool
134  -> TypeClassData
135makeTypeClassData args m s deps = TypeClassData args m s deps determinedArgs coveringSets
136  where
137    argumentIndices = [0 .. length args - 1]
138
139    -- each argument determines themselves
140    identities = (\i -> (i, [i])) <$> argumentIndices
141
142    -- list all the edges in the graph: for each fundep an edge exists for each determiner to each determined
143    contributingDeps = M.fromListWith (++) $ identities ++ do
144      fd <- deps
145      src <- fdDeterminers fd
146      (src, fdDetermined fd) : map (, []) (fdDetermined fd)
147
148    -- build a graph of which arguments determine other arguments
149    (depGraph, fromVertex, fromKey) = G.graphFromEdges ((\(n, v) -> (n, n, ordNub v)) <$> M.toList contributingDeps)
150
151    -- do there exist any arguments that contribute to `arg` that `arg` doesn't contribute to
152    isFunDepDetermined :: Int -> Bool
153    isFunDepDetermined arg = case fromKey arg of
154      Nothing -> internalError "Unknown argument index in makeTypeClassData"
155      Just v -> let contributesToVar = G.reachable (G.transposeG depGraph) v
156                    varContributesTo = G.reachable depGraph v
157                in any (`notElem` varContributesTo) contributesToVar
158
159    -- find all the arguments that are determined
160    determinedArgs :: S.Set Int
161    determinedArgs = S.fromList $ filter isFunDepDetermined argumentIndices
162
163    argFromVertex :: G.Vertex -> Int
164    argFromVertex index = let (_, arg, _) = fromVertex index in arg
165
166    isVertexDetermined :: G.Vertex -> Bool
167    isVertexDetermined = isFunDepDetermined . argFromVertex
168
169    -- from an scc find the non-determined args
170    sccNonDetermined :: Tree G.Vertex -> Maybe [Int]
171    sccNonDetermined tree
172      -- if any arg in an scc is determined then all of them are
173      | isVertexDetermined (rootLabel tree) = Nothing
174      | otherwise = Just (argFromVertex <$> toList tree)
175
176    -- find the covering sets
177    coveringSets :: S.Set (S.Set Int)
178    coveringSets = let funDepSets = sequence (mapMaybe sccNonDetermined (G.scc depGraph))
179                   in S.fromList (S.fromList <$> funDepSets)
180
181-- | The visibility of a name in scope
182data NameVisibility
183  = Undefined
184  -- ^ The name is defined in the current binding group, but is not visible
185  | Defined
186  -- ^ The name is defined in the another binding group, or has been made visible by a function binder
187  deriving (Show, Eq, Generic)
188
189instance NFData NameVisibility
190instance Serialise NameVisibility
191
192-- | A flag for whether a name is for an private or public value - only public values will be
193-- included in a generated externs file.
194data NameKind
195  = Private
196  -- ^ A private value introduced as an artifact of code generation (class instances, class member
197  -- accessors, etc.)
198  | Public
199  -- ^ A public value for a module member or foreign import declaration
200  | External
201  -- ^ A name for member introduced by foreign import
202  deriving (Show, Eq, Generic)
203
204instance NFData NameKind
205instance Serialise NameKind
206
207-- | The kinds of a type
208data TypeKind
209  = DataType DataDeclType [(Text, Maybe SourceType, Role)] [(ProperName 'ConstructorName, [SourceType])]
210  -- ^ Data type
211  | TypeSynonym
212  -- ^ Type synonym
213  | ExternData [Role]
214  -- ^ Foreign data
215  | LocalTypeVariable
216  -- ^ A local type variable
217  | ScopedTypeVar
218  -- ^ A scoped type variable
219  deriving (Show, Eq, Generic)
220
221instance NFData TypeKind
222instance Serialise TypeKind
223
224-- | The type ('data' or 'newtype') of a data type declaration
225data DataDeclType
226  = Data
227  -- ^ A standard data constructor
228  | Newtype
229  -- ^ A newtype constructor
230  deriving (Show, Eq, Ord, Generic)
231
232instance NFData DataDeclType
233instance Serialise DataDeclType
234
235showDataDeclType :: DataDeclType -> Text
236showDataDeclType Data = "data"
237showDataDeclType Newtype = "newtype"
238
239instance A.ToJSON DataDeclType where
240  toJSON = A.toJSON . showDataDeclType
241
242instance A.FromJSON DataDeclType where
243  parseJSON = A.withText "DataDeclType" $ \case
244    "data" -> return Data
245    "newtype" -> return Newtype
246    other -> fail $ "invalid type: '" ++ T.unpack other ++ "'"
247
248-- | Construct a ProperName in the Prim module
249primName :: Text -> Qualified (ProperName a)
250primName = Qualified (Just C.Prim) . ProperName
251
252-- | Construct a 'ProperName' in the @Prim.NAME@ module.
253primSubName :: Text -> Text -> Qualified (ProperName a)
254primSubName sub =
255  Qualified (Just $ ModuleName $ C.prim <> "." <> sub) . ProperName
256
257primKind :: Text -> SourceType
258primKind = primTy
259
260primSubKind :: Text -> Text -> SourceType
261primSubKind sub = TypeConstructor nullSourceAnn . primSubName sub
262
263-- | Kind of ground types
264kindType :: SourceType
265kindType = primKind C.typ
266
267kindConstraint :: SourceType
268kindConstraint = primKind C.constraint
269
270kindSymbol :: SourceType
271kindSymbol = primKind C.symbol
272
273kindDoc :: SourceType
274kindDoc = primSubKind C.typeError C.doc
275
276kindOrdering :: SourceType
277kindOrdering = primSubKind C.moduleOrdering C.kindOrdering
278
279kindRowList :: SourceType -> SourceType
280kindRowList = TypeApp nullSourceAnn (primSubKind C.moduleRowList C.kindRowList)
281
282kindRow :: SourceType -> SourceType
283kindRow = TypeApp nullSourceAnn (primKind C.row)
284
285kindOfREmpty :: SourceType
286kindOfREmpty = tyForall "k" kindType (kindRow (tyVar "k"))
287
288-- | Construct a type in the Prim module
289primTy :: Text -> SourceType
290primTy = TypeConstructor nullSourceAnn . primName
291
292-- | Type constructor for functions
293tyFunction :: SourceType
294tyFunction = primTy "Function"
295
296-- | Type constructor for strings
297tyString :: SourceType
298tyString = primTy "String"
299
300-- | Type constructor for strings
301tyChar :: SourceType
302tyChar = primTy "Char"
303
304-- | Type constructor for numbers
305tyNumber :: SourceType
306tyNumber = primTy "Number"
307
308-- | Type constructor for integers
309tyInt :: SourceType
310tyInt = primTy "Int"
311
312-- | Type constructor for booleans
313tyBoolean :: SourceType
314tyBoolean = primTy "Boolean"
315
316-- | Type constructor for arrays
317tyArray :: SourceType
318tyArray = primTy "Array"
319
320-- | Type constructor for records
321tyRecord :: SourceType
322tyRecord = primTy "Record"
323
324tyVar :: Text -> SourceType
325tyVar = TypeVar nullSourceAnn
326
327tyForall :: Text -> SourceType -> SourceType -> SourceType
328tyForall var k ty = ForAll nullSourceAnn var (Just k) ty Nothing
329
330-- | Smart constructor for function types
331function :: SourceType -> SourceType -> SourceType
332function = TypeApp nullSourceAnn . TypeApp nullSourceAnn tyFunction
333
334-- To make reading the kind signatures below easier
335(-:>) :: SourceType -> SourceType -> SourceType
336(-:>) = function
337infixr 4 -:>
338
339primClass :: Qualified (ProperName 'TypeName) -> (SourceType -> SourceType) -> [(Qualified (ProperName 'TypeName), (SourceType, TypeKind))]
340primClass name mkKind =
341  [ let k = mkKind kindConstraint
342    in (name, (k, ExternData (nominalRolesForKind k)))
343  , let k = mkKind kindType
344    in (dictTypeName <$> name, (k, TypeSynonym))
345  ]
346
347-- | The primitive types in the external environment with their
348-- associated kinds. There are also pseudo `Fail`, `Warn`, and `Partial` types
349-- that correspond to the classes with the same names.
350primTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
351primTypes =
352  M.fromList
353    [ (primName "Type",             (kindType, ExternData []))
354    , (primName "Constraint",       (kindType, ExternData []))
355    , (primName "Symbol",           (kindType, ExternData []))
356    , (primName "Row",              (kindType -:> kindType, ExternData [Phantom]))
357    , (primName "Function",         (kindType -:> kindType -:> kindType, ExternData [Representational, Representational]))
358    , (primName "Array",            (kindType -:> kindType, ExternData [Representational]))
359    , (primName "Record",           (kindRow kindType -:> kindType, ExternData [Representational]))
360    , (primName "String",           (kindType, ExternData []))
361    , (primName "Char",             (kindType, ExternData []))
362    , (primName "Number",           (kindType, ExternData []))
363    , (primName "Int",              (kindType, ExternData []))
364    , (primName "Boolean",          (kindType, ExternData []))
365    , (primName "Partial",          (kindConstraint, ExternData []))
366    ]
367
368-- | This 'Map' contains all of the prim types from all Prim modules.
369allPrimTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
370allPrimTypes = M.unions
371  [ primTypes
372  , primBooleanTypes
373  , primCoerceTypes
374  , primOrderingTypes
375  , primRowTypes
376  , primRowListTypes
377  , primSymbolTypes
378  , primTypeErrorTypes
379  ]
380
381primBooleanTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
382primBooleanTypes =
383  M.fromList
384    [ (primSubName C.moduleBoolean "True", (tyBoolean, ExternData []))
385    , (primSubName C.moduleBoolean "False", (tyBoolean, ExternData []))
386    ]
387
388primCoerceTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
389primCoerceTypes =
390  M.fromList $ mconcat
391    [ primClass (primSubName C.moduleCoerce "Coercible") (\kind -> tyForall "k" kindType $ tyVar "k" -:> tyVar "k" -:> kind)
392    ]
393
394primOrderingTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
395primOrderingTypes =
396  M.fromList
397    [ (primSubName C.moduleOrdering "Ordering", (kindType, ExternData []))
398    , (primSubName C.moduleOrdering "LT", (kindOrdering, ExternData []))
399    , (primSubName C.moduleOrdering "EQ", (kindOrdering, ExternData []))
400    , (primSubName C.moduleOrdering "GT", (kindOrdering, ExternData []))
401    ]
402
403primRowTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
404primRowTypes =
405  M.fromList $ mconcat
406    [ primClass (primSubName C.moduleRow "Union") (\kind -> tyForall "k" kindType $ kindRow (tyVar "k") -:> kindRow (tyVar "k") -:> kindRow (tyVar "k") -:> kind)
407    , primClass (primSubName C.moduleRow "Nub")   (\kind -> tyForall "k" kindType $ kindRow (tyVar "k") -:> kindRow (tyVar "k") -:> kind)
408    , primClass (primSubName C.moduleRow "Lacks") (\kind -> tyForall "k" kindType $ kindSymbol -:> kindRow (tyVar "k") -:> kind)
409    , primClass (primSubName C.moduleRow "Cons")  (\kind -> tyForall "k" kindType $ kindSymbol -:> tyVar "k" -:> kindRow (tyVar "k") -:> kindRow (tyVar "k") -:> kind)
410    ]
411
412primRowListTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
413primRowListTypes =
414  M.fromList $
415    [ (primSubName C.moduleRowList "RowList", (kindType -:> kindType, ExternData [Phantom]))
416    , (primSubName C.moduleRowList "Cons", (tyForall "k" kindType $ kindSymbol -:> tyVar "k" -:> kindRowList (tyVar "k") -:> kindRowList (tyVar "k"), ExternData [Phantom, Phantom, Phantom]))
417    , (primSubName C.moduleRowList "Nil", (tyForall "k" kindType $ kindRowList (tyVar "k"), ExternData []))
418    ] <> mconcat
419    [ primClass (primSubName C.moduleRowList "RowToList")  (\kind -> tyForall "k" kindType $ kindRow (tyVar "k") -:> kindRowList (tyVar "k") -:> kind)
420    ]
421
422primSymbolTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
423primSymbolTypes =
424  M.fromList $ mconcat
425    [ primClass (primSubName C.moduleSymbol "Append")  (\kind -> kindSymbol -:> kindSymbol -:> kindSymbol -:> kind)
426    , primClass (primSubName C.moduleSymbol "Compare") (\kind -> kindSymbol -:> kindSymbol -:> kindOrdering -:> kind)
427    , primClass (primSubName C.moduleSymbol "Cons")    (\kind -> kindSymbol -:> kindSymbol -:> kindSymbol -:> kind)
428    ]
429
430primTypeErrorTypes :: M.Map (Qualified (ProperName 'TypeName)) (SourceType, TypeKind)
431primTypeErrorTypes =
432  M.fromList $
433    [ (primSubName C.typeError "Doc", (kindType, ExternData []))
434    , (primSubName C.typeError "Fail", (kindDoc -:> kindConstraint, ExternData [Nominal]))
435    , (primSubName C.typeError "Warn", (kindDoc -:> kindConstraint, ExternData [Nominal]))
436    , (primSubName C.typeError "Text", (kindSymbol -:> kindDoc, ExternData [Phantom]))
437    , (primSubName C.typeError "Quote", (kindType -:> kindDoc, ExternData [Phantom]))
438    , (primSubName C.typeError "QuoteLabel", (kindSymbol -:> kindDoc, ExternData [Phantom]))
439    , (primSubName C.typeError "Beside", (kindDoc -:> kindDoc -:> kindDoc, ExternData [Phantom, Phantom]))
440    , (primSubName C.typeError "Above", (kindDoc -:> kindDoc -:> kindDoc, ExternData [Phantom, Phantom]))
441    ] <> mconcat
442    [ primClass (primSubName C.typeError "Fail") (\kind -> kindDoc -:> kind)
443    , primClass (primSubName C.typeError "Warn") (\kind -> kindDoc -:> kind)
444    ]
445
446-- | The primitive class map. This just contains the `Partial` class.
447-- `Partial` is used as a kind of magic constraint for partial functions.
448primClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
449primClasses =
450  M.fromList
451    [ (primName "Partial", makeTypeClassData [] [] [] [] True)
452    ]
453
454-- | This contains all of the type classes from all Prim modules.
455allPrimClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
456allPrimClasses = M.unions
457  [ primClasses
458  , primCoerceClasses
459  , primRowClasses
460  , primRowListClasses
461  , primSymbolClasses
462  , primTypeErrorClasses
463  ]
464
465primCoerceClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
466primCoerceClasses =
467  M.fromList
468    -- class Coercible (a :: k) (b :: k)
469    [ (primSubName C.moduleCoerce "Coercible", makeTypeClassData
470        [ ("a", Just (tyVar "k"))
471        , ("b", Just (tyVar "k"))
472        ] [] [] [] True)
473    ]
474
475primRowClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
476primRowClasses =
477  M.fromList
478    -- class Union (left :: Row k) (right :: Row k) (union :: Row k) | left right -> union, right union -> left, union left -> right
479    [ (primSubName C.moduleRow "Union", makeTypeClassData
480        [ ("left", Just (kindRow (tyVar "k")))
481        , ("right", Just (kindRow (tyVar "k")))
482        , ("union", Just (kindRow (tyVar "k")))
483        ] [] []
484        [ FunctionalDependency [0, 1] [2]
485        , FunctionalDependency [1, 2] [0]
486        , FunctionalDependency [2, 0] [1]
487        ] True)
488
489    -- class Nub (original :: Row k) (nubbed :: Row k) | original -> nubbed
490    , (primSubName C.moduleRow "Nub", makeTypeClassData
491        [ ("original", Just (kindRow (tyVar "k")))
492        , ("nubbed", Just (kindRow (tyVar "k")))
493        ] [] []
494        [ FunctionalDependency [0] [1]
495        ] True)
496
497    -- class Lacks (label :: Symbol) (row :: Row k)
498    , (primSubName C.moduleRow "Lacks", makeTypeClassData
499        [ ("label", Just kindSymbol)
500        , ("row", Just (kindRow (tyVar "k")))
501        ] [] [] [] True)
502
503    -- class RowCons (label :: Symbol) (a :: k) (tail :: Row k) (row :: Row k) | label tail a -> row, label row -> tail a
504    , (primSubName C.moduleRow "Cons", makeTypeClassData
505        [ ("label", Just kindSymbol)
506        , ("a", Just (tyVar "k"))
507        , ("tail", Just (kindRow (tyVar "k")))
508        , ("row", Just (kindRow (tyVar "k")))
509        ] [] []
510        [ FunctionalDependency [0, 1, 2] [3]
511        , FunctionalDependency [0, 3] [1, 2]
512        ] True)
513    ]
514
515primRowListClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
516primRowListClasses =
517  M.fromList
518    -- class RowToList (row :: Row k) (list :: RowList k) | row -> list
519    [ (primSubName C.moduleRowList "RowToList", makeTypeClassData
520        [ ("row", Just (kindRow (tyVar "k")))
521        , ("list", Just (kindRowList (tyVar "k")))
522        ] [] []
523        [ FunctionalDependency [0] [1]
524        ] True)
525    ]
526
527primSymbolClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
528primSymbolClasses =
529  M.fromList
530    -- class Append (left :: Symbol) (right :: Symbol) (appended :: Symbol) | left right -> appended, right appended -> left, appended left -> right
531    [ (primSubName C.moduleSymbol "Append", makeTypeClassData
532        [ ("left", Just kindSymbol)
533        , ("right", Just kindSymbol)
534        , ("appended", Just kindSymbol)
535        ] [] []
536        [ FunctionalDependency [0, 1] [2]
537        , FunctionalDependency [1, 2] [0]
538        , FunctionalDependency [2, 0] [1]
539        ] True)
540
541    -- class Compare (left :: Symbol) (right :: Symbol) (ordering :: Ordering) | left right -> ordering
542    , (primSubName C.moduleSymbol "Compare", makeTypeClassData
543        [ ("left", Just kindSymbol)
544        , ("right", Just kindSymbol)
545        , ("ordering", Just kindOrdering)
546        ] [] []
547        [ FunctionalDependency [0, 1] [2]
548        ] True)
549
550    -- class Cons (head :: Symbol) (tail :: Symbol) (symbol :: Symbol) | head tail -> symbol, symbol -> head tail
551    , (primSubName C.moduleSymbol "Cons", makeTypeClassData
552        [ ("head", Just kindSymbol)
553        , ("tail", Just kindSymbol)
554        , ("symbol", Just kindSymbol)
555        ] [] []
556        [ FunctionalDependency [0, 1] [2]
557        , FunctionalDependency [2] [0, 1]
558        ] True)
559    ]
560
561primTypeErrorClasses :: M.Map (Qualified (ProperName 'ClassName)) TypeClassData
562primTypeErrorClasses =
563  M.fromList
564    -- class Fail (message :: Symbol)
565    [ (primSubName C.typeError "Fail", makeTypeClassData
566        [("message", Just kindDoc)] [] [] [] True)
567
568    -- class Warn (message :: Symbol)
569    , (primSubName C.typeError "Warn", makeTypeClassData
570        [("message", Just kindDoc)] [] [] [] True)
571    ]
572
573-- | Finds information about data constructors from the current environment.
574lookupConstructor :: Environment -> Qualified (ProperName 'ConstructorName) -> (DataDeclType, ProperName 'TypeName, SourceType, [Ident])
575lookupConstructor env ctor =
576  fromMaybe (internalError "Data constructor not found") $ ctor `M.lookup` dataConstructors env
577
578-- | Finds information about values from the current environment.
579lookupValue :: Environment -> Qualified Ident -> Maybe (SourceType, NameKind, NameVisibility)
580lookupValue env ident = ident `M.lookup` names env
581
582dictTypeName' :: Text -> Text
583dictTypeName' = (<> "$Dict")
584
585dictTypeName :: ProperName a -> ProperName a
586dictTypeName = ProperName . dictTypeName' . runProperName
587
588isDictTypeName :: ProperName a -> Bool
589isDictTypeName = T.isSuffixOf "$Dict" . runProperName
590
591-- |
592-- Given the kind of a type, generate a list @Nominal@ roles. This is used for
593-- opaque foreign types as well as type classes.
594nominalRolesForKind :: Type a -> [Role]
595nominalRolesForKind k = replicate (kindArity k) Nominal
596
597kindArity :: Type a -> Int
598kindArity = length . fst . unapplyKinds
599
600unapplyKinds :: Type a -> ([Type a], Type a)
601unapplyKinds = go [] where
602  go kinds (TypeApp _ (TypeApp _ fn k1) k2)
603    | eqType fn tyFunction = go (k1 : kinds) k2
604  go kinds (ForAll _ _ _ k _) = go kinds k
605  go kinds k = (reverse kinds, k)
606