1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
9 , Descriptor(Descriptor)
18 , int, float, char, string, bool, never
19 , vec2, vec3, vec4, mat4, texture
32import Control.Monad.State.Strict (StateT, liftIO)
33import qualified Control.Monad.State.Strict as State
34import Data.Foldable (foldrM)
35import qualified Data.Map.Strict as Map
36import Data.Word (Word32)
38import qualified AST.Canonical as Can
39import qualified AST.Module.Name as ModuleName
40import qualified AST.Utils.Type as Type
41import qualified Elm.Name as N
42import qualified Reporting.Annotation as A
43import qualified Reporting.Error.Type as E
44import qualified Reporting.Region as R
45import qualified Type.Error as ET
46import qualified Type.UnionFind as UF
56 | CEqual R.Region E.Category Type (E.Expected Type)
57 | CLocal R.Region N.Name (E.Expected Type)
58 | CForeign R.Region N.Name Can.Annotation (E.Expected Type)
59 | CPattern R.Region E.PCategory Type (E.PExpected Type)
62 { _rigidVars :: [Variable]
63 , _flexVars :: [Variable]
64 , _header :: Map.Map N.Name (A.Located Type)
65 , _headerCon :: Constraint
66 , _bodyCon :: Constraint
70exists :: [Variable] -> Constraint -> Constraint
71exists flexVars constraint =
72 CLet [] flexVars Map.empty constraint CTrue
84 = App1 ModuleName.Canonical N.Name [Variable]
85 | Fun1 Variable Variable
87 | Record1 (Map.Map N.Name Variable) Variable
89 | Tuple1 Variable Variable (Maybe Variable)
94 | AliasN ModuleName.Canonical N.Name [(N.Name, Type)] Type
96 | AppN ModuleName.Canonical N.Name [Type]
99 | RecordN (Map.Map N.Name Type) Type
101 | TupleN Type Type (Maybe Type)
110 { _content :: Content
113 , _copy :: Maybe Variable
118 = FlexVar (Maybe N.Name)
119 | FlexSuper SuperType (Maybe N.Name)
121 | RigidSuper SuperType N.Name
123 | Alias ModuleName.Canonical N.Name [(N.Name,Variable)] Variable
135makeDescriptor :: Content -> Descriptor
136makeDescriptor content =
137 Descriptor content noRank noMark Nothing
158newtype Mark = Mark Word32
172getVarNamesMark :: Mark
177{-# INLINE nextMark #-}
178nextMark :: Mark -> Mark
179nextMark (Mark mark) =
191(==>) :: Type -> Type -> Type
202int = AppN ModuleName.basics "Int" []
205{-# NOINLINE float #-}
207float = AppN ModuleName.basics "Float" []
212char = AppN ModuleName.char "Char" []
215{-# NOINLINE string #-}
217string = AppN ModuleName.string "String" []
222bool = AppN ModuleName.basics "Bool" []
225{-# NOINLINE never #-}
227never = AppN ModuleName.basics "Never" []
236vec2 = AppN ModuleName.vector2 "Vec2" []
241vec3 = AppN ModuleName.vector3 "Vec3" []
246vec4 = AppN ModuleName.vector4 "Vec4" []
251mat4 = AppN ModuleName.matrix4 "Mat4" []
254{-# NOINLINE texture #-}
256texture = AppN ModuleName.texture "Texture" []
260-- MAKE FLEX VARIABLES
263mkFlexVar :: IO Variable
265 UF.fresh flexVarDescriptor
268{-# NOINLINE flexVarDescriptor #-}
269flexVarDescriptor :: Descriptor
271 makeDescriptor unnamedFlexVar
274{-# NOINLINE unnamedFlexVar #-}
275unnamedFlexVar :: Content
284mkFlexNumber :: IO Variable
286 UF.fresh flexNumberDescriptor
289{-# NOINLINE flexNumberDescriptor #-}
290flexNumberDescriptor :: Descriptor
291flexNumberDescriptor =
292 makeDescriptor (unnamedFlexSuper Number)
295unnamedFlexSuper :: SuperType -> Content
296unnamedFlexSuper super =
297 FlexSuper super Nothing
301-- MAKE NAMED VARIABLES
304nameToFlex :: N.Name -> IO Variable
306 UF.fresh $ makeDescriptor $
307 maybe FlexVar FlexSuper (toSuper name) (Just name)
310nameToRigid :: N.Name -> IO Variable
312 UF.fresh $ makeDescriptor $
313 maybe RigidVar RigidSuper (toSuper name) name
316toSuper :: N.Name -> Maybe SuperType
318 if N.startsWith "number" name then
321 else if N.startsWith "comparable" name then
324 else if N.startsWith "appendable" name then
327 else if N.startsWith "compappend" name then
338toAnnotation :: Variable -> IO Can.Annotation
339toAnnotation variable =
340 do userNames <- getVarNames variable Map.empty
341 (tipe, NameState freeVars _ _ _ _ _) <-
342 State.runStateT (variableToCanType variable) (makeNameState userNames)
343 return $ Can.Forall freeVars tipe
346variableToCanType :: Variable -> StateT NameState IO Can.Type
347variableToCanType variable =
348 do (Descriptor content _ _ _) <- liftIO $ UF.get variable
356 return (Can.TVar name)
359 do name <- getFreshVarName
360 liftIO $ UF.modify variable (\desc -> desc { _content = FlexVar (Just name) })
361 return (Can.TVar name)
363 FlexSuper super maybeName ->
366 return (Can.TVar name)
369 do name <- getFreshSuperName super
370 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
371 return (Can.TVar name)
374 return (Can.TVar name)
377 return (Can.TVar name)
379 Alias home name args realVariable ->
380 do canArgs <- traverse (traverse variableToCanType) args
381 canType <- variableToCanType realVariable
382 return (Can.TAlias home name canArgs (Can.Filled canType))
385 error "cannot handle Error types in variableToCanType"
388termToCanType :: FlatType -> StateT NameState IO Can.Type
391 App1 home name args ->
392 Can.TType home name <$> traverse variableToCanType args
396 <$> variableToCanType a
397 <*> variableToCanType b
400 return $ Can.TRecord Map.empty Nothing
402 Record1 fields extension ->
403 do canFields <- traverse fieldToCanType fields
404 canExt <- Type.iteratedDealias <$> variableToCanType extension
407 Can.TRecord subFields subExt ->
408 Can.TRecord (Map.union subFields canFields) subExt
411 Can.TRecord canFields (Just name)
414 error "Used toAnnotation on a type that is not well-formed"
421 <$> variableToCanType a
422 <*> variableToCanType b
423 <*> traverse variableToCanType maybeC
426fieldToCanType :: Variable -> StateT NameState IO Can.FieldType
427fieldToCanType variable =
428 do tipe <- variableToCanType variable
429 return (Can.FieldType 0 tipe)
436toErrorType :: Variable -> IO ET.Type
437toErrorType variable =
438 do userNames <- getVarNames variable Map.empty
439 State.evalStateT (variableToErrorType variable) (makeNameState userNames)
442variableToErrorType :: Variable -> StateT NameState IO ET.Type
443variableToErrorType variable =
444 do descriptor <- liftIO $ UF.get variable
445 let mark = _mark descriptor
446 if mark == occursMark
451 do liftIO $ UF.modify variable (\desc -> desc { _mark = occursMark })
452 errType <- contentToErrorType variable (_content descriptor)
453 liftIO $ UF.modify variable (\desc -> desc { _mark = mark })
457contentToErrorType :: Variable -> Content -> StateT NameState IO ET.Type
458contentToErrorType variable content =
466 return (ET.FlexVar name)
469 do name <- getFreshVarName
470 liftIO $ UF.modify variable (\desc -> desc { _content = FlexVar (Just name) })
471 return (ET.FlexVar name)
473 FlexSuper super maybeName ->
476 return (ET.FlexSuper (superToSuper super) name)
479 do name <- getFreshSuperName super
480 liftIO $ UF.modify variable (\desc -> desc { _content = FlexSuper super (Just name) })
481 return (ET.FlexSuper (superToSuper super) name)
484 return (ET.RigidVar name)
486 RigidSuper super name ->
487 return (ET.RigidSuper (superToSuper super) name)
489 Alias home name args realVariable ->
490 do errArgs <- traverse (traverse variableToErrorType) args
491 errType <- variableToErrorType realVariable
492 return (ET.Alias home name errArgs errType)
498superToSuper :: SuperType -> ET.Super
502 Comparable -> ET.Comparable
503 Appendable -> ET.Appendable
504 CompAppend -> ET.CompAppend
507termToErrorType :: FlatType -> StateT NameState IO ET.Type
508termToErrorType term =
510 App1 home name args ->
511 ET.Type home name <$> traverse variableToErrorType args
514 do arg <- variableToErrorType a
515 result <- variableToErrorType b
518 ET.Lambda arg1 arg2 others ->
519 ET.Lambda arg arg1 (arg2:others)
522 ET.Lambda arg result []
525 return $ ET.Record Map.empty ET.Closed
527 Record1 fields extension ->
528 do errFields <- traverse variableToErrorType fields
529 errExt <- ET.iteratedDealias <$> variableToErrorType extension
532 ET.Record subFields subExt ->
533 ET.Record (Map.union subFields errFields) subExt
536 ET.Record errFields (ET.FlexOpen ext)
539 ET.Record errFields (ET.RigidOpen ext)
542 error "Used toErrorType on a type that is not well-formed"
549 <$> variableToErrorType a
550 <*> variableToErrorType b
551 <*> traverse variableToErrorType maybeC
555-- MANAGE FRESH VARIABLE NAMES
560 { _taken :: Map.Map N.Name ()
563 , _comparables :: Int
564 , _appendables :: Int
565 , _compAppends :: Int
569makeNameState :: Map.Map N.Name Variable -> NameState
571 NameState (Map.map (const ()) taken) 0 0 0 0 0
578getFreshVarName :: (Monad m) => StateT NameState m N.Name
580 do index <- State.gets _normals
581 taken <- State.gets _taken
582 let (name, newIndex, newTaken) = getFreshVarNameHelp index taken
583 State.modify $ \state -> state { _taken = newTaken, _normals = newIndex }
587getFreshVarNameHelp :: Int -> Map.Map N.Name () -> (N.Name, Int, Map.Map N.Name ())
588getFreshVarNameHelp index taken =
593 chr = N.fromLetter letter
594 name = if postfix <= 0 then chr else N.addIndex chr postfix
596 if Map.member name taken then
597 getFreshVarNameHelp (index + 1) taken
599 ( name, index + 1, Map.insert name () taken )
606getFreshSuperName :: (Monad m) => SuperType -> StateT NameState m N.Name
607getFreshSuperName super =
610 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
613 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
616 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
619 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
622getFreshSuper :: (Monad m) => N.Name -> (NameState -> Int) -> (Int -> NameState -> NameState) -> StateT NameState m N.Name
623getFreshSuper prefix getter setter =
624 do index <- State.gets getter
625 taken <- State.gets _taken
626 let (name, newIndex, newTaken) = getFreshSuperHelp prefix index taken
627 State.modify (\state -> setter newIndex state { _taken = newTaken })
631getFreshSuperHelp :: N.Name -> Int -> Map.Map N.Name () -> (N.Name, Int, Map.Map N.Name ())
632getFreshSuperHelp prefix index taken =
635 if index <= 0 then prefix else N.addIndex prefix index
637 if Map.member name taken then
638 getFreshSuperHelp prefix (index + 1) taken
641 ( name, index + 1, Map.insert name () taken )
645-- GET ALL VARIABLE NAMES
648getVarNames :: Variable -> Map.Map N.Name Variable -> IO (Map.Map N.Name Variable)
649getVarNames var takenNames =
650 do (Descriptor content rank mark copy) <- UF.get var
651 if mark == getVarNamesMark
652 then return takenNames
654 do UF.set var (Descriptor content rank getVarNamesMark copy)
665 addName 0 name var (FlexVar . Just) takenNames
667 FlexSuper super maybeName ->
673 addName 0 name var (FlexSuper super . Just) takenNames
676 addName 0 name var RigidVar takenNames
678 RigidSuper super name ->
679 addName 0 name var (RigidSuper super) takenNames
682 foldrM getVarNames takenNames (map snd args)
684 Structure flatType ->
687 foldrM getVarNames takenNames args
690 getVarNames arg =<< getVarNames body takenNames
695 Record1 fields extension ->
696 getVarNames extension =<<
697 foldrM getVarNames takenNames (Map.elems fields)
702 Tuple1 a b Nothing ->
703 getVarNames a =<< getVarNames b takenNames
705 Tuple1 a b (Just c) ->
706 getVarNames a =<< getVarNames b =<< getVarNames c takenNames
710-- REGISTER NAME / RENAME DUPLICATES
713addName :: Int -> N.Name -> Variable -> (N.Name -> Content) -> Map.Map N.Name Variable -> IO (Map.Map N.Name Variable)
714addName index givenName var makeContent takenNames =
720 N.addSafeIndex givenName index
722 case Map.lookup indexedName takenNames of
724 do if indexedName == givenName then return () else
725 UF.modify var $ \(Descriptor _ rank mark copy) ->
726 Descriptor (makeContent indexedName) rank mark copy
727 return $ Map.insert indexedName var takenNames
730 do same <- UF.equivalent var otherVar
732 then return takenNames
733 else addName (index + 1) givenName var makeContent takenNames
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list