1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
5import Control.Monad (when)
6import Control.Monad.State (StateT, liftIO)
7import qualified Control.Monad.State as State
8import qualified Data.Char as Char
9import qualified Data.Map as Map
10import Data.Monoid ((<>))
11import qualified Data.Text as Text
12import qualified Data.UnionFind.IO as UF
13import Data.Text (Text)
15import qualified AST.Type as T
16import qualified AST.Variable as Var
17import qualified Reporting.Annotation as A
18import qualified Reporting.Error.Type as Error
19import qualified Reporting.Region as R
35 Constraint Type Variable
50 | Record1 (Map.Map Text a) a
55 | AliasN Var.Canonical [(Text, TermN a)] (TermN a)
57 | TermN (Term1 (TermN a))
60record :: Map.Map Text (TermN a) -> TermN a -> TermN a
62 TermN (Record1 fs rec)
74 , _copy :: Maybe Variable
79 = Structure (Term1 Variable)
81 | Var Flex (Maybe Super) (Maybe Text)
82 | Alias Var.Canonical [(Text,Variable)] Variable
120getVarNamesMark :: Int
132 | CEqual Error.Hint R.Region a a
133 | CAnd [Constraint a b]
134 | CLet [Scheme a b] (Constraint a b)
135 | CInstance R.Region SchemeName a
138type SchemeName = Text
141data Scheme a b = Scheme
142 { _rigidQuantifiers :: [b]
143 , _flexibleQuantifiers :: [b]
144 , _constraint :: Constraint a b
145 , _header :: Map.Map Text (A.Located a)
156(==>) :: Type -> Type -> Type
161(<|) :: TermN a -> TermN a -> TermN a
170mkDescriptor :: Content -> Descriptor
171mkDescriptor content =
180mkAtom :: Var.Canonical -> IO Variable
182 UF.fresh $ mkDescriptor (Atom name)
185mkVar :: Maybe Super -> IO Variable
187 UF.fresh $ mkDescriptor (Var Flex maybeSuper Nothing)
190mkNamedVar :: Flex -> Text -> IO Variable
191mkNamedVar flex name =
192 UF.fresh $ mkDescriptor $ Var flex (toSuper name) (Just name)
195toSuper :: Text -> Maybe Super
197 if Text.isPrefixOf "number" name then
200 else if Text.isPrefixOf "comparable" name then
203 else if Text.isPrefixOf "appendable" name then
214monoscheme :: Map.Map Text (A.Located a) -> Scheme a b
216 Scheme [] [] CTrue headers
222(/\) :: Constraint a b -> Constraint a b -> Constraint a b
230-- ex qs constraint == exists qs. constraint
231ex :: [Variable] -> TypeConstraint -> TypeConstraint
233 CLet [Scheme [] fqs constraint Map.empty] CTrue
236forall :: [Variable] -> TypeConstraint -> TypeConstraint
237forall rqs constraint =
238 CLet [Scheme rqs [] constraint Map.empty] CTrue
241exists :: (Type -> IO TypeConstraint) -> IO TypeConstraint
243 do v <- mkVar Nothing
244 ex [v] <$> f (VarN v)
247existsNumber :: (Type -> IO TypeConstraint) -> IO TypeConstraint
249 do v <- mkVar (Just Number)
250 ex [v] <$> f (VarN v)
254-- CONVERT TO SOURCE TYPES
257-- TODO: Attach resulting type to the descriptor so that you
258-- never have to do extra work, particularly nice for aliased types
259toSrcType :: Variable -> IO T.Canonical
261 do takenNames <- State.execStateT (getVarNames variable) Map.empty
262 State.evalStateT (variableToSrcType variable) (makeNameState takenNames)
265variableToSrcType :: Variable -> StateT NameState IO T.Canonical
266variableToSrcType variable =
267 do descriptor <- liftIO $ UF.descriptor variable
268 let mark = _mark descriptor
269 if mark == occursMark
274 do liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = occursMark })
275 srcType <- contentToSrcType variable (_content descriptor)
276 liftIO $ UF.modifyDescriptor variable (\desc -> desc { _mark = mark })
280contentToSrcType :: Variable -> Content -> StateT NameState IO T.Canonical
281contentToSrcType variable content =
289 Var _ _ (Just name) ->
292 Var flex maybeSuper Nothing ->
293 do freshName <- getFreshName maybeSuper
294 liftIO $ UF.modifyDescriptor variable $ \desc ->
295 desc { _content = Var flex maybeSuper (Just freshName) }
296 return (T.Var freshName)
298 Alias name args realVariable ->
299 do srcArgs <- traverse (traverse variableToSrcType) args
300 srcType <- variableToSrcType realVariable
301 return (T.Aliased name srcArgs (T.Filled srcType))
307termToSrcType :: Term1 Variable -> StateT NameState IO T.Canonical
311 do srcFunc <- variableToSrcType func
312 srcArg <- variableToSrcType arg
315 return (T.App f (args ++ [srcArg]))
318 return (T.App srcFunc [srcArg])
322 <$> variableToSrcType a
323 <*> variableToSrcType b
326 return $ T.Record [] Nothing
328 Record1 fields extension ->
329 do srcFields <- Map.toList <$> traverse variableToSrcType fields
330 srcExt <- T.iteratedDealias <$> variableToSrcType extension
333 T.Record subFields subExt ->
334 T.Record (subFields ++ srcFields) subExt
337 T.Record srcFields (Just srcExt)
340 error "Used toSrcType on a type that is not well-formed"
344-- MANAGE FRESH VARIABLE NAMES
347data NameState = NameState
348 { _taken :: TakenNames
351 , _comparables :: Int
352 , _appendables :: Int
353 , _compAppends :: Int
357type TakenNames = Map.Map Text Variable
360makeNameState :: TakenNames -> NameState
362 NameState taken 0 0 0 0 0
365getFreshName :: (Monad m) => Maybe Super -> StateT NameState m Text
366getFreshName maybeSuper =
369 do index <- State.gets _normals
370 taken <- State.gets _taken
371 let (uniqueName, newIndex) = getFreshNormal index taken
372 State.modify (\state -> state { _normals = newIndex })
376 getFreshSuper "number" _numbers (\index state -> state { _numbers = index })
379 getFreshSuper "comparable" _comparables (\index state -> state { _comparables = index })
382 getFreshSuper "appendable" _appendables (\index state -> state { _appendables = index })
385 getFreshSuper "compappend" _compAppends (\index state -> state { _compAppends = index })
388getFreshNormal :: Int -> TakenNames -> (Text, Int)
389getFreshNormal index taken =
395 Char.chr (97 + letter)
398 Text.pack (if postfix <= 0 then [char] else char : show postfix)
400 if Map.member name taken then
401 getFreshNormal (index + 1) taken
410 -> (NameState -> Int)
411 -> (Int -> NameState -> NameState)
412 -> StateT NameState m Text
413getFreshSuper name getter setter =
414 do index <- State.gets getter
415 taken <- State.gets _taken
416 let (uniqueName, newIndex) = getFreshSuperHelp name index taken
417 State.modify (setter newIndex)
421getFreshSuperHelp :: Text -> Int -> TakenNames -> (Text, Int)
422getFreshSuperHelp name index taken =
425 if index <= 0 then name else name <> Text.pack (show index)
427 if Map.member newName taken then
428 getFreshSuperHelp name (index + 1) taken
435-- GET ALL VARIABLE NAMES
438getVarNames :: Variable -> StateT TakenNames IO ()
440 do desc <- liftIO $ UF.descriptor var
441 case _mark desc == getVarNamesMark of
446 do liftIO $ UF.setDescriptor var (desc { _mark = getVarNamesMark })
447 case _content desc of
457 Var flex maybeSuper (Just name) ->
458 do oldTaken <- State.get
459 newTaken <- liftIO $ addVarName 0 name var flex maybeSuper oldTaken
462 Alias _ args realVar ->
463 do mapM_ (getVarNames . snd) args
466 Structure (App1 func arg) ->
470 Structure (Fun1 arg body) ->
474 Structure EmptyRecord1 ->
477 Structure (Record1 fields extension) ->
478 do mapM_ getVarNames fields
479 getVarNames extension
482addVarName :: Int -> Text -> Variable -> Flex -> Maybe Super -> TakenNames -> IO TakenNames
483addVarName index givenName var flex maybeSuper taken =
486 makeIndexedName givenName index
488 case Map.lookup name taken of
490 do when (name /= givenName) $ UF.modifyDescriptor var $ \desc ->
491 desc { _content = Var flex maybeSuper (Just name) }
492 return $ Map.insert name var taken
495 do same <- UF.equivalent var otherVar
498 else addVarName (index + 1) givenName var flex maybeSuper taken
501makeIndexedName :: Text -> Int -> Text
502makeIndexedName name index =
506 else if Char.isDigit (Text.last name) then
507 name <> Text.pack ('_' : show index)
510 name <> Text.pack (show index)
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