on master help sign in
New module chaser, for better dependency checking and rebuilding

Now treats each source file separately, building a tree of dependencies, and rebuilding if any dependencies have updated. In particular, this fixes a problem with stale definitions hanging around when building packages, and has required some fixes to imports in the library. Will need a 'make relib'.

commit0aca9f2b5de1b2c8ea3e642edcd4baad728ada71 authorEdwin Brady <ecb10@st-andrews.ac.uk> dateMon 26 Aug 2013, 23:35 (13 years ago) parent205ebd0
20 files changed+271−22
idris.cabal+3−2 lib/Data/Bits.idr+2 lib/Data/BoundedList.idr+3−1 lib/Data/Morphisms.idr+1−1 lib/Data/SortedMap.idr+1 lib/Data/SortedSet.idr+1 lib/Data/Vect/Quantifiers.idr+2 lib/Debug/Trace.idr+1 lib/Decidable/Equality.idr+1−1 lib/Language/Reflection.idr+1−1 lib/Language/Reflection/Utils.idr+3 lib/Uninhabited.idr+2 src/Idris/AbsSyntax.hs+5−1 src/Idris/Chaser.hs+132 src/Idris/ElabTerm.hs+1−1 src/Idris/IBC.hs+12−5 src/Idris/Imports.hs+1−1 src/Idris/Parser.hs+28−2 src/Idris/REPL.hs+70−5 test/test025/test025.idr+1−1
idris.cabal+3−2
@@ -258,7 +258,7 @@ Executable idris
258258 Idris.Coverage, Idris.IBC, Idris.Unlit,
259259 Idris.DataOpts, Idris.Transforms, Idris.DSL,
260260 Idris.UnusedArgs, Idris.Docs, Idris.Completion,
261− Idris.PartialEval, Idris.Providers,
261+ Idris.PartialEval, Idris.Providers, Idris.Chaser,
262262
263263 Util.Pretty, Util.System, Util.DynamicLinker,
264264 Pkg.Package, Pkg.PParser,
@@ -273,7 +273,8 @@ Executable idris
273273 Paths_idris
274274
275275 Build-depends: base>=4 && <5, parsec>=3, mtl, Cabal,
276− haskeline>=0.7, split, directory,
276+ haskeline>=0.7, split, directory>=1.2,
277+ time>=1.4,
277278 containers, process, transformers, filepath,
278279 directory, binary, bytestring, text, pretty,
279280 language-java>=0.2.2, libffi,
lib/Data/Bits.idr+2
@@ -1,5 +1,7 @@
11module Data.Bits
22
3+import Prelude
4+
35%default total
46
57divCeil : Nat -> Nat -> Nat
lib/Data/BoundedList.idr+3−1
@@ -1,5 +1,7 @@
11module Data.BoundedList
22
3+import Prelude
4+
35%access public
46%default total
57
@@ -90,4 +92,4 @@ pad {n=S n'} (x :: xs) padding = x :: pad {n=n'} xs padding
9092
9193zeroBoundIsEmpty : (xs : BoundedList a 0) -> xs = the (BoundedList a 0) []
9294zeroBoundIsEmpty [] = refl
93−zeroBoundIsEmpty (_ :: _) impossible
95+zeroBoundIsEmpty (_ :: _) impossible
lib/Data/Morphisms.idr+1−1
@@ -1,6 +1,6 @@
11module Data.Morphisms
22
3−import Builtins
3+import Prelude
44
55%access public
66
lib/Data/SortedMap.idr+1
@@ -1,5 +1,6 @@
11module Data.SortedMap
22
3+import Prelude
34-- TODO: write merge and split
45
56data Tree : Nat -> Type -> Type -> Type where
lib/Data/SortedSet.idr+1
@@ -1,5 +1,6 @@
11module Data.SortedSet
22
3+import Prelude
34import Data.SortedMap
45
56-- TODO: add intersection, union, difference
lib/Data/Vect/Quantifiers.idr+2
@@ -1,5 +1,7 @@
11module Data.Vect.Quantifiers
22
3+import Prelude
4+
35data Any : (P : a -> Type) -> Vect n a -> Type where
46 Here : {P : a -> Type} -> {xs : Vect n a} -> P x -> Any P (x :: xs)
57 There : {P : a -> Type} -> {xs : Vect n a} -> Any P xs -> Any P (x :: xs)
lib/Debug/Trace.idr+1
@@ -1,5 +1,6 @@
11module Debug.Trace
22
3+import Prelude
34import IO
45
56trace : String -> a -> a
lib/Decidable/Equality.idr+1−1
@@ -1,6 +1,6 @@
11module Decidable.Equality
22
3−import Builtins
3+import Prelude
44
55--------------------------------------------------------------------------------
66-- Utility lemmas
lib/Language/Reflection.idr+1−1
@@ -1,6 +1,6 @@
11module Language.Reflection
22
3−import Prelude.Vect
3+import Prelude
44
55%access public
66
lib/Language/Reflection/Utils.idr+3
@@ -1,5 +1,8 @@
11module Language.Reflection.Utils
22
3+import Prelude
4+import Language.Reflection
5+
36--------------------------------------------------------
47-- Tactic construction conveniences
58--------------------------------------------------------
lib/Uninhabited.idr+2
@@ -1,5 +1,7 @@
11module Uninhabited
22
3+import Prelude
4+
35class Uninhabited t where
46 total uninhabited : t -> _|_
57
src/Idris/AbsSyntax.hs+5−1
@@ -112,7 +112,7 @@ addToCG n cg
112112
113113addCoercion :: Name -> Idris ()
114114addCoercion n = do i <- getIState
115− putIState $ i { idris_coercions = n : idris_coercions i }
115+ putIState $ i { idris_coercions = nub $ n : idris_coercions i }
116116
117117addDocStr :: Name -> String -> Idris ()
118118addDocStr n doc
@@ -318,6 +318,10 @@ setCmdLine opts = do i <- getIState
318318 let iopts = idris_options i
319319 putIState $ i { idris_options = iopts { opt_cmdline = opts } }
320320
321+getCmdLine :: Idris [Opt]
322+getCmdLine = do i <- getIState
323+ return (opt_cmdline (idris_options i))
324+
321325getDumpDefun :: Idris (Maybe FilePath)
322326getDumpDefun = do i <- getIState
323327 return $ findC (opt_cmdline (idris_options i))
src/Idris/Chaser.hsnew file+132
@@ -0,0 +1,132 @@
1+module Idris.Chaser(buildTree, getModuleFiles, ModuleTree(..)) where
2+
3+import Idris.Parser
4+import Idris.AbsSyntax
5+import Idris.Imports
6+import Idris.Unlit
7+import Idris.Error
8+import Idris.IBC
9+
10+import System.FilePath
11+import System.Directory
12+import Data.Time.Clock
13+import Control.Monad.Trans
14+import Control.Monad.State
15+import Data.List
16+
17+import Debug.Trace
18+
19+data ModuleTree = MTree { mod_path :: IFileType,
20+ mod_needsRecheck :: Bool,
21+ mod_time :: UTCTime,
22+ mod_deps :: [ModuleTree] }
23+ deriving Show
24+
25+latest :: UTCTime -> [ModuleTree] -> UTCTime
26+latest tm [] = tm
27+latest tm (m : ms) = latest (max tm (mod_time m)) (ms ++ mod_deps m)
28+
29+-- Given a module tree, return the list of files to be loaded. If any
30+-- module has a descendent which needs reloading, return its source, otherwise
31+-- return the IBC
32+
33+getModuleFiles :: [ModuleTree] -> [IFileType]
34+getModuleFiles ts = nub $ execState (modList ts) [] where
35+ modList :: [ModuleTree] -> State [IFileType] ()
36+ modList [] = return ()
37+ modList (m : ms) = do modTree [] m; modList ms
38+
39+ modTree path (MTree p rechk tm deps)
40+ = do let file = chkReload rechk p
41+ -- Needs rechecking if 'rechk' is true, or if any of the
42+ -- modification times in 'deps' are later than tm
43+ let depMod = latest tm deps
44+ let needsRechk = rechk || depMod > tm
45+
46+ st <- get
47+ if needsRechk then put $ nub (getSrc file : updateToSrc path st)
48+ else put $ nub (file : st)
49+-- when (not (ibc p) || rechk) $
50+ mapM_ (modTree (getSrc p : path)) deps
51+
52+ ibc (IBC _ _) = True
53+ ibc _ = False
54+
55+ chkReload False p = p
56+ chkReload True (IBC fn src) = chkReload True src
57+ chkReload True p = p
58+
59+ getSrc (IBC fn src) = getSrc src
60+ getSrc f = f
61+
62+ updateToSrc path [] = []
63+ updateToSrc path (x : xs) = if getSrc x `elem` path
64+ then getSrc x : updateToSrc path xs
65+ else x : updateToSrc path xs
66+
67+getIModTime (IBC i _) = getModificationTime i
68+getIModTime (IDR i) = getModificationTime i
69+getIModTime (LIDR i) = getModificationTime i
70+
71+buildTree :: [FilePath] -> -- already guaranteed built
72+ FilePath -> Idris [ModuleTree]
73+buildTree built fp = btree [] fp where
74+ btree done f =
75+ do i <- getIState
76+ let file = takeWhile (/= ' ') f
77+ iLOG $ "CHASING " ++ show file
78+ ibcsd <- valIBCSubDir i
79+ ids <- allImportDirs i
80+ fp <- liftIO $ findImport ids ibcsd file
81+ mt <- liftIO $ getIModTime fp
82+ if (file `elem` built)
83+ then return [MTree fp False mt []]
84+ else if file `elem` done
85+ then return []
86+ else mkChildren fp
87+
88+ where mkChildren (LIDR fn) = do ms <- children True fn (f:done)
89+ mt <- liftIO $ getModificationTime fn
90+ return [MTree (LIDR fn) True mt ms]
91+ mkChildren (IDR fn) = do ms <- children False fn (f:done)
92+ mt <- liftIO $ getModificationTime fn
93+ return [MTree (IDR fn) True mt ms]
94+ mkChildren (IBC fn src)
95+ = do srcexist <- liftIO $ doesFileExist (getSrcFile src)
96+ ms <- if srcexist then
97+ do [MTree _ _ _ ms'] <- mkChildren src
98+ return ms'
99+ else return []
100+ mt <- idrisCatch (liftIO $ getModificationTime fn)
101+ (\c -> liftIO $ getIModTime src)
102+ ok <- checkIBCUpToDate fn src
103+ return [MTree (IBC fn src) ok mt ms]
104+
105+ getSrcFile (IBC _ src) = getSrcFile src
106+ getSrcFile (LIDR src) = src
107+ getSrcFile (IDR src) = src
108+
109+ -- FIXME: It's also not up to date if anything it imports has
110+ -- been modified since its own ibc has.
111+
112+ checkIBCUpToDate fn (LIDR src) = older fn src
113+ checkIBCUpToDate fn (IDR src) = older fn src
114+
115+ older ibc src = do exist <- liftIO $ doesFileExist src
116+ if exist then do
117+ ibct <- liftIO $ getModificationTime ibc
118+ srct <- liftIO $ getModificationTime src
119+ return (srct > ibct)
120+ else return False
121+
122+ children :: Bool -> FilePath -> [FilePath] -> Idris [ModuleTree]
123+ children lit f done = idrisCatch
124+ (do exist <- liftIO $ doesFileExist f
125+ if exist then do
126+ file_in <- liftIO $ readFile f
127+ file <- if lit then tclift $ unlit f file_in else return file_in
128+ (_, modules, _, _) <- parseImports f file
129+ ms <- mapM (btree done) modules
130+ return (concat ms)
131+ else return []) -- IBC with no source available
132+ (\c -> return []) -- error, can't chase modules here
src/Idris/ElabTerm.hs+1−1
@@ -667,7 +667,7 @@ resolveTC depth fn ist
667667 scopeOnly <- needsDefault t tc ttypes
668668 let insts_in = findInstances ist t
669669 let insts = if scopeOnly then filter chaser insts_in
670− else insts_in
670+ else insts_in
671671 tm <- get_term
672672-- traceWhen (depth > 6) ("GOAL: " ++ show t ++ "\nTERM: " ++ show tm) $
673673-- (tryAll (map elabTC (map fst (ctxtAlist (tt_ctxt ist)))))
src/Idris/IBC.hs+12−5
@@ -23,7 +23,7 @@ import Debug.Trace
2323import Paths_idris
2424
2525ibcVersion :: Word8
26−ibcVersion = 33
26+ibcVersion = 34
2727
2828data IBCFile = IBCFile { ver :: Word8,
2929 sourcefile :: FilePath,
@@ -135,13 +135,13 @@ ibc i (IBCTrans t) f = return f { ibc_transforms = t : ibc_transforms f }
135135process :: IBCFile -> FilePath -> Idris ()
136136process i fn
137137 | ver i /= ibcVersion = do iLOG "ibc out of date"
138− fail "Incorrect ibc version"
138+ fail "Incorrect ibc version --- please rebuild"
139139 | otherwise =
140140 do srcok <- liftIO $ doesFileExist (sourcefile i)
141141 when srcok $ liftIO $ timestampOlder (sourcefile i) fn
142142 v <- verbose
143143 quiet <- getQuiet
144− when (v && srcok && not quiet) $ iputStrLn $ "Skipping " ++ sourcefile i
144+-- when (v && srcok && not quiet) $ iputStrLn $ "Skipping " ++ sourcefile i
145145 pImports (ibc_imports i)
146146 pImps (ibc_implicits i)
147147 pFixes (ibc_fixes i)
@@ -208,10 +208,17 @@ pStatics ss = mapM_ (\ (n, s) ->
208208 ss
209209
210210pClasses :: [(Name, ClassInfo)] -> Idris ()
211−pClasses cs = mapM_ (\ (n, c) ->
211+pClasses cs = mapM_ (\ (n, c) ->
212212 do i <- getIState
213+ -- Don't lose instances from previous IBCs, which
214+ -- could have loaded in any order
215+ let is = case lookupCtxt n (idris_classes i) of
216+ [CI _ _ _ _ ins] -> ins
217+ _ -> []
218+ let c' = c { class_instances =
219+ class_instances c ++ is }
213220 putIState (i { idris_classes
214− = addDef n c (idris_classes i) }))
221+ = addDef n c' (idris_classes i) }))
215222 cs
216223
217224pInstances :: [(Bool, Name, Name)] -> Idris ()
src/Idris/Imports.hs+1−1
@@ -10,7 +10,7 @@ import System.Directory
1010import Control.Monad.State
1111
1212data IFileType = IDR FilePath | LIDR FilePath | IBC FilePath IFileType
13− deriving Eq
13+ deriving (Show, Eq)
1414
1515srcPath :: FilePath -> FilePath
1616srcPath fp = let (n, ext) = splitExtension fp in
src/Idris/Parser.hs+28−2
@@ -90,6 +90,26 @@ loadModule f
9090 iputStrLn msg
9191 return "")
9292
93+loadFromIFile :: IFileType -> Idris ()
94+loadFromIFile i@(IBC fn src)
95+ = do iLOG $ "Skipping " ++ getSrcFile i
96+ idrisCatch (loadIBC fn)
97+ (\c -> do fail $ fn ++ " failed " ++ show c)
98+-- loadFromIFile src)
99+ where
100+ getSrcFile (IDR fn) = fn
101+ getSrcFile (LIDR fn) = fn
102+ getSrcFile (IBC f src) = getSrcFile src
103+
104+loadFromIFile (IDR fn) = loadSource' False fn
105+loadFromIFile (LIDR fn) = loadSource' True fn
106+
107+loadSource' lidr r
108+ = idrisCatch (loadSource lidr r)
109+ (\e -> do let msg = show e
110+ setErrLine (getErrLine msg)
111+ iputStrLn msg)
112+
93113loadSource :: Bool -> FilePath -> Idris ()
94114loadSource lidr f
95115 = do iLOG ("Reading " ++ f)
@@ -100,7 +120,7 @@ loadSource lidr f
100120 (mname, modules, rest, pos) <- parseImports f file
101121 i <- getIState
102122 putIState (i { default_access = Hidden })
103− mapM_ loadModule modules
123+-- mapM_ loadModule modules
104124 clearIBC -- start a new .ibc file
105125 mapM_ (addIBC . IBCImport) modules
106126 ds' <- parseProg (defaultSyntax {syn_namespace = reverse mname })
@@ -128,6 +148,8 @@ loadSource lidr f
128148 mapM_ checkDeclTotality (idris_totcheck i)
129149 iLOG ("Finished " ++ f)
130150 ibcsd <- valIBCSubDir i
151+ iLOG "Universe checking"
152+ iucheck
131153 let ibc = ibcPathNoFallback ibcsd f
132154 i <- getIState
133155 addHides (hide_list i)
@@ -173,7 +195,8 @@ parseImports fname input
173195 pos <- getPosition
174196 return ((mname, ps, rest, pos), i)) i fname input of
175197 Left err -> fail (show err)
176− Right (x, i) -> do putIState i
198+ Right (x, i) -> do -- Discard state updates (there should be
199+ -- none anyway)
177200 return x
178201
179202pHeader :: IParser [String]
@@ -295,6 +318,9 @@ parseProg syn fname input pos
295318 i' <- getState
296319 return (concat ps, i')) i fname input of
297320 Left err -> do iputStrLn (show err)
321+ let errl = sourceLine (errorPos err)
322+ i <- getIState
323+ putIState (i { errLine = Just errl })
298324 return []
299325 Right (x, i) -> do putIState i
300326 return (collect x)
src/Idris/REPL.hs+70−5
@@ -18,6 +18,8 @@ import Idris.Docs
1818import Idris.Help
1919import Idris.Completion
2020import Idris.IdeSlave
21+import Idris.Chaser
22+import Idris.Imports
2123
2224import Paths_idris
2325import Util.System
@@ -213,7 +215,7 @@ processInput cmd orig inputs
213215 Right Reload ->
214216 do putIState (orig { idris_options = idris_options i })
215217 clearErr
216− mods <- mapM loadModule inputs
218+ mods <- loadInputs inputs
217219 return (Just inputs)
218220 Right (Load f) ->
219221 do putIState (orig { idris_options = idris_options i })
@@ -264,7 +266,7 @@ edit f orig
264266 liftIO $ system cmd
265267 clearErr
266268 putIState (orig { idris_options = idris_options i })
267− loadModule f
269+ loadInputs [f]
268270 iucheck
269271 return ()
270272 where getEditor env | Just ed <- lookup "EDITOR" env = ed
@@ -640,6 +642,69 @@ replSettings = setComplete replCompletion defaultSettings
640642idris :: [Opt] -> IO IState
641643idris opts = execStateT (idrisMain opts) idrisInit
642644
645+loadInputs :: [FilePath] -> Idris ()
646+loadInputs inputs
647+ = do ist <- getIState
648+ -- if we're in --check and not outputting anything, don't bother
649+ -- loading, as it gets really slow if there's lots of modules in
650+ -- a package (instead, reload all at the end to check for
651+ -- consistency only)
652+ opts <- getCmdLine
653+
654+ let loadCode = case opt getOutput opts of
655+ [] -> not (NoREPL `elem` opts)
656+ _ -> True
657+
658+ -- For each ifile list, check it and build ibcs in the same clean IState
659+ -- so that they don't interfere with each other when checking
660+
661+ let ninputs = zip [1..] inputs
662+ ifiles <- mapM (\(num, input) ->
663+ do putIState ist
664+ v <- verbose
665+-- when v $ iputStrLn $ "(" ++ show num ++ "/" ++
666+-- show (length inputs) ++
667+-- ") " ++ input
668+ modTree <- buildTree
669+ (map snd (take (num-1) ninputs))
670+ input
671+ let ifiles = getModuleFiles modTree
672+ iLOG ("MODULE TREE : " ++ show modTree)
673+ iLOG ("RELOAD: " ++ show ifiles)
674+ when (not (all ibc ifiles) || loadCode) $ tryLoad ifiles
675+ return ifiles)
676+ ninputs
677+ inew <- getIState
678+ -- to check everything worked consistently (in particular, will catch
679+ -- if the ibc version is out of date) if we weren't loading per
680+ -- module
681+ case errLine inew of
682+ Nothing ->
683+ do putIState ist
684+ when (not loadCode) $ tryLoad $ nub (concat ifiles)
685+ _ -> return ()
686+ putIState inew
687+-- inew <- getIState
688+-- case errLine inew of
689+-- Nothing ->
690+-- -- Then, load all the ibcs again, if there were no errors.
691+-- do putIState ist
692+-- modTree <- mapM (buildTree (map snd ninputs)) inputs
693+-- let ifiless = map getModuleFiles modTree
694+-- mapM_ loadFromIFile (concat ifiless)
695+-- _ -> return ()
696+ where -- load all files, stop if any fail
697+ tryLoad :: [IFileType] -> Idris ()
698+ tryLoad [] = return ()
699+ tryLoad (f : fs) = do loadFromIFile f
700+ inew <- getIState
701+ case errLine inew of
702+ Nothing -> tryLoad fs
703+ _ -> return () -- error, stop
704+
705+ ibc (IBC _ _) = True
706+ ibc _ = False
707+
643708idrisMain :: [Opt] -> Idris ()
644709idrisMain opts =
645710 do let inputs = opt getFile opts
@@ -707,9 +772,9 @@ idrisMain opts =
707772 return ()
708773 when (runrepl && not quiet && not idesl && not (isJust script)) $ iputStrLn banner
709774 ist <- getIState
710− mods <- mapM loadModule inputs
711− iLOG "Universe checking"
712− iucheck
775+
776+ loadInputs inputs
777+
713778 ok <- noErrors
714779 when ok $ case output of
715780 [] -> return ()
test/test025/test025.idr+1−1
@@ -26,7 +26,7 @@ testMemory = do Src :- allocate 5
2626 res <- Dst :- peek 1 (S(S(S(S Z)))) oh
2727 Dst :- free
2828 return (map (prim__zextB8_Int) res)
29−
29+
3030main : IO ()
3131main = do ioe_run (run [Dst := (), Src := ()] testMemory)
3232 (\err => print err) (\ok => print ok)