@@ -66,19 +66,20 @@ data Env =
6666 , _root :: FilePath
6767 , _pkg :: Pkg.Name
6868 , _srcDirs :: [FilePath]
69+ , _buildID :: Details.BuildID
6970 , _locals :: Map.Map ModuleName.Raw Details.Local
7071 , _foreigns :: Map.Map ModuleName.Raw Details.Foreign
7172 }
7273
7374
7475makeEnv :: Reporting.BKey -> FilePath -> Details.Details -> Env
75−makeEnv key root (Details.Details _ validOutline locals foreigns _) =
76+makeEnv key root (Details.Details _ validOutline buildID locals foreigns _) =
7677 case validOutline of
7778 Details.ValidApp srcDirs ->
78− Env key root Pkg.dummyName (NE.toList srcDirs) locals foreigns
79+ Env key root Pkg.dummyName (NE.toList srcDirs) buildID locals foreigns
7980
8081 Details.ValidPkg pkg _ _ ->
81− Env key root pkg ["src"] locals foreigns
82+ Env key root pkg ["src"] buildID locals foreigns
8283
8384
8485
@@ -238,7 +239,7 @@ crawlDeps env mvar deps blockedValue =
238239
239240
240241crawlModule :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> IO Status
241−crawlModule env@(Env _ root pkg srcDirs locals foreigns) mvar docsNeed name =
242+crawlModule env@(Env _ root pkg srcDirs buildID locals foreigns) mvar docsNeed name =
242243 do let fileName = ModuleName.toFilePath name <.> "elm"
243244 let inRoot path = File.exists (root </> path)
244245
@@ -251,18 +252,15 @@ crawlModule env@(Env _ root pkg srcDirs locals foreigns) mvar docsNeed name =
251252 return $ SBadImport $ Import.Ambiguous path [] dep deps
252253
253254 Nothing ->
254− case Map.lookup name locals of
255− Nothing ->
256− crawlFile env mvar docsNeed name path =<< File.getTime path
255+ do newTime <- File.getTime path
256+ case Map.lookup name locals of
257+ Nothing ->
258+ crawlFile env mvar docsNeed name path newTime buildID
257259
258− Just local@(Details.Local oldPath oldTime deps _) ->
259− if path /= oldPath
260− then crawlFile env mvar docsNeed name path =<< File.getTime path
261− else
262− do newTime <- File.getTime path
263− if oldTime /= newTime || needsDocs docsNeed
264− then crawlFile env mvar docsNeed name path newTime
265− else crawlDeps env mvar deps (SCached local)
260+ Just local@(Details.Local oldPath oldTime deps _ lastChange _) ->
261+ if path /= oldPath || oldTime /= newTime || needsDocs docsNeed
262+ then crawlFile env mvar docsNeed name path newTime lastChange
263+ else crawlDeps env mvar deps (SCached local)
266264
267265 p1:p2:ps ->
268266 return $ SBadImport $ Import.AmbiguousLocal p1 p2 ps
@@ -285,8 +283,8 @@ crawlModule env@(Env _ root pkg srcDirs locals foreigns) mvar docsNeed name =
285283 return $ SBadImport Import.NotFound
286284
287285
288−crawlFile :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> FilePath -> File.Time -> IO Status
289−crawlFile env@(Env _ root pkg _ _ _) mvar docsNeed expectedName path time =
286+crawlFile :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> FilePath -> File.Time -> Details.BuildID -> IO Status
287+crawlFile env@(Env _ root pkg _ buildID _ _) mvar docsNeed expectedName path time lastChange =
290288 do source <- File.readUtf8 (root </> path)
291289
292290 case Parse.fromByteString pkg source of
@@ -302,7 +300,7 @@ crawlFile env@(Env _ root pkg _ _ _) mvar docsNeed expectedName path time =
302300 if expectedName == actualName then
303301 let
304302 deps = map Src.getImportName imports
305− local = Details.Local path time deps (any isMain values)
303+ local = Details.Local path time deps (any isMain values) lastChange buildID
306304 in
307305 crawlDeps env mvar deps (SChanged local source modul docsNeed)
308306 else
@@ -325,7 +323,7 @@ type ResultDict =
325323data Result
326324 = RNew !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
327325 | RSame !Details.Local !I.Interface !Opt.LocalGraph !(Maybe Docs.Module)
328− | RCached Bool (MVar CachedInterface)
326+ | RCached Bool Details.BuildID (MVar CachedInterface)
329327 | RNotFound Import.Problem
330328 | RProblem Error.Module
331329 | RBlocked
@@ -340,11 +338,11 @@ data CachedInterface
340338
341339
342340checkModule :: Env -> Dependencies -> MVar ResultDict -> ModuleName.Raw -> Status -> IO Result
343−checkModule env@(Env _ root pkg _ _ _) foreigns resultsMVar name status =
341+checkModule env@(Env _ root pkg _ _ _ _) foreigns resultsMVar name status =
344342 case status of
345− SCached local@(Details.Local path time deps hasMain) ->
343+ SCached local@(Details.Local path time deps hasMain lastChange lastCompile) ->
346344 do results <- readMVar resultsMVar
347− depsStatus <- checkDeps root results deps
345+ depsStatus <- checkDeps root results deps lastCompile
348346 case depsStatus of
349347 DepsChange ifaces ->
350348 do source <- File.readUtf8 path
@@ -356,7 +354,7 @@ checkModule env@(Env _ root pkg _ _ _) foreigns resultsMVar name status =
356354
357355 DepsSame _ _ ->
358356 do mvar <- newMVar Unneeded
359− return (RCached hasMain mvar)
357+ return (RCached hasMain lastChange mvar)
360358
361359 DepsBlock ->
362360 return RBlocked
@@ -371,9 +369,9 @@ checkModule env@(Env _ root pkg _ _ _) foreigns resultsMVar name status =
371369 Left err ->
372370 Error.BadSyntax err
373371
374− SChanged local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) docsNeed ->
372+ SChanged local@(Details.Local path time deps _ _ lastCompile) source modul@(Src.Module _ _ _ imports _ _ _ _ _) docsNeed ->
375373 do results <- readMVar resultsMVar
376− depsStatus <- checkDeps root results deps
374+ depsStatus <- checkDeps root results deps lastCompile
377375 case depsStatus of
378376 DepsChange ifaces ->
379377 compile env docsNeed local source ifaces modul
@@ -418,29 +416,45 @@ data DepsStatus
418416 | DepsNotFound (NE.List (ModuleName.Raw, Import.Problem))
419417
420418
421−checkDeps :: FilePath -> ResultDict -> [ModuleName.Raw] -> IO DepsStatus
422−checkDeps root results deps =
423− checkDepsHelp root results deps [] [] [] [] False
419+checkDeps :: FilePath -> ResultDict -> [ModuleName.Raw] -> Details.BuildID -> IO DepsStatus
420+checkDeps root results deps lastCompile =
421+ checkDepsHelp root results deps [] [] [] [] False 0 lastCompile
424422
425423
426424type Dep = (ModuleName.Raw, I.Interface)
427425type CDep = (ModuleName.Raw, MVar CachedInterface)
428426
429427
430−checkDepsHelp :: FilePath -> ResultDict -> [ModuleName.Raw] -> [Dep] -> [Dep] -> [CDep] -> [(ModuleName.Raw,Import.Problem)] -> Bool -> IO DepsStatus
431−checkDepsHelp root results deps new same cached importProblems isBlocked =
428+checkDepsHelp :: FilePath -> ResultDict -> [ModuleName.Raw] -> [Dep] -> [Dep] -> [CDep] -> [(ModuleName.Raw,Import.Problem)] -> Bool -> Details.BuildID -> Details.BuildID -> IO DepsStatus
429+checkDepsHelp root results deps new same cached importProblems isBlocked lastDepChange lastCompile =
432430 case deps of
433431 dep:otherDeps ->
434432 do result <- readMVar (results ! dep)
435433 case result of
436− RNew _ iface _ _ -> checkDepsHelp root results otherDeps ((dep,iface) : new) same cached importProblems isBlocked
437− RSame _ iface _ _ -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
438− RCached _ mvar -> checkDepsHelp root results otherDeps new same ((dep,mvar) : cached) importProblems isBlocked
439− RNotFound prob -> checkDepsHelp root results otherDeps new same cached ((dep,prob) : importProblems) True
440− RProblem _ -> checkDepsHelp root results otherDeps new same cached importProblems True
441− RBlocked -> checkDepsHelp root results otherDeps new same cached importProblems True
442− RForeign iface -> checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked
443− RKernel -> checkDepsHelp root results otherDeps new same cached importProblems isBlocked
434+ RNew (Details.Local _ _ _ _ lastChange _) iface _ _ ->
435+ checkDepsHelp root results otherDeps ((dep,iface) : new) same cached importProblems isBlocked (max lastChange lastDepChange) lastCompile
436+
437+ RSame (Details.Local _ _ _ _ lastChange _) iface _ _ ->
438+ checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked (max lastChange lastDepChange) lastCompile
439+
440+ RCached _ lastChange mvar ->
441+ checkDepsHelp root results otherDeps new same ((dep,mvar) : cached) importProblems isBlocked (max lastChange lastDepChange) lastCompile
442+
443+ RNotFound prob ->
444+ checkDepsHelp root results otherDeps new same cached ((dep,prob) : importProblems) True lastDepChange lastCompile
445+
446+ RProblem _ ->
447+ checkDepsHelp root results otherDeps new same cached importProblems True lastDepChange lastCompile
448+
449+ RBlocked ->
450+ checkDepsHelp root results otherDeps new same cached importProblems True lastDepChange lastCompile
451+
452+ RForeign iface ->
453+ checkDepsHelp root results otherDeps new ((dep,iface) : same) cached importProblems isBlocked lastDepChange lastCompile
454+
455+ RKernel ->
456+ checkDepsHelp root results otherDeps new same cached importProblems isBlocked lastDepChange lastCompile
457+
444458
445459 [] ->
446460 case reverse importProblems of
@@ -451,7 +465,7 @@ checkDepsHelp root results deps new same cached importProblems isBlocked =
451465 if isBlocked then
452466 return $ DepsBlock
453467
454− else if null new then
468+ else if null new && lastDepChange <= lastCompile then
455469 return $ DepsSame same cached
456470
457471 else
@@ -466,7 +480,7 @@ checkDepsHelp root results deps new same cached importProblems isBlocked =
466480
467481
468482toImportErrors :: Env -> ResultDict -> [Src.Import] -> NE.List (ModuleName.Raw, Import.Problem) -> NE.List Import.Error
469−toImportErrors (Env _ _ _ _ locals foreigns) results imports problems =
483+toImportErrors (Env _ _ _ _ _ locals foreigns) results imports problems =
470484 let
471485 knownModules =
472486 Set.unions
@@ -600,12 +614,12 @@ addToGraph name status graph =
600614 let
601615 dependencies =
602616 case status of
603− SCached (Details.Local _ _ deps _) -> deps
604− SChanged (Details.Local _ _ deps _) _ _ _ -> deps
605− SBadImport _ -> []
606− SBadSyntax _ _ _ _ -> []
607− SForeign _ -> []
608− SKernel -> []
617+ SCached (Details.Local _ _ deps _ _ _) -> deps
618+ SChanged (Details.Local _ _ deps _ _ _) _ _ _ -> deps
619+ SBadImport _ -> []
620+ SBadSyntax _ _ _ _ -> []
621+ SForeign _ -> []
622+ SKernel -> []
609623 in
610624 (name, name, dependencies) : graph
611625
@@ -633,9 +647,9 @@ checkUniqueMains insides smains =
633647mainStatusToNamePathPair :: MainStatus -> Maybe (ModuleName.Raw, OneOrMore.OneOrMore FilePath)
634648mainStatusToNamePathPair smain =
635649 case smain of
636− SInside _ -> Nothing
637− SOutsideOk (Details.Local path _ _ _) _ modul -> Just (Src.getName modul, OneOrMore.one path)
638− SOutsideErr _ -> Nothing
650+ SInside _ -> Nothing
651+ SOutsideOk (Details.Local path _ _ _ _ _) _ modul -> Just (Src.getName modul, OneOrMore.one path)
652+ SOutsideErr _ -> Nothing
639653
640654
641655checkOutside :: ModuleName.Raw -> OneOrMore.OneOrMore FilePath -> Either Exit.BuildProjectProblem FilePath
@@ -648,12 +662,12 @@ checkOutside name paths =
648662checkInside :: ModuleName.Raw -> FilePath -> Status -> Either Exit.BuildProjectProblem ()
649663checkInside name p1 status =
650664 case status of
651− SCached (Details.Local p2 _ _ _) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
652− SChanged (Details.Local p2 _ _ _) _ _ _ -> Left (Exit.BP_MainNameDuplicate name p1 p2)
653− SBadImport _ -> Right ()
654− SBadSyntax _ _ _ _ -> Right ()
655− SForeign _ -> Right ()
656− SKernel -> Right ()
665+ SCached (Details.Local p2 _ _ _ _ _) -> Left (Exit.BP_MainNameDuplicate name p1 p2)
666+ SChanged (Details.Local p2 _ _ _ _ _) _ _ _ -> Left (Exit.BP_MainNameDuplicate name p1 p2)
667+ SBadImport _ -> Right ()
668+ SBadSyntax _ _ _ _ -> Right ()
669+ SForeign _ -> Right ()
670+ SKernel -> Right ()
657671
658672
659673
@@ -661,7 +675,7 @@ checkInside name p1 status =
661675
662676
663677compile :: Env -> DocsNeed -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO Result
664−compile (Env key root pkg _ _ _) docsNeed local@(Details.Local path time _ _) source ifaces modul =
678+compile (Env key root pkg _ buildID _ _) docsNeed (Details.Local path time deps main lastChange _) source ifaces modul =
665679 case Compile.compile pkg ifaces modul of
666680 Right (Compile.Artifacts canonical annotations objects) ->
667681 do let name = Src.getName modul
@@ -674,12 +688,14 @@ compile (Env key root pkg _ _ _) docsNeed local@(Details.Local path time _ _) so
674688 Just oldi | oldi == iface ->
675689 do -- iface should be fully forced by equality check
676690 Reporting.report key Reporting.BDone
691+ let local = Details.Local path time deps main lastChange buildID
677692 return (RSame local iface objects docs)
678693
679694 _ ->
680695 do -- iface may be lazy still
681696 File.writeBinary elmi iface
682697 Reporting.report key Reporting.BDone
698+ let local = Details.Local path time deps main buildID buildID
683699 return (RNew local iface objects docs)
684700
685701 Left err ->
@@ -692,9 +708,9 @@ compile (Env key root pkg _ _ _) docsNeed local@(Details.Local path time _ _) so
692708
693709
694710writeDetails :: FilePath -> Details.Details -> Map.Map ModuleName.Raw Result -> IO ()
695−writeDetails root (Details.Details time outline locals foreigns extras) results =
711+writeDetails root (Details.Details time outline buildID locals foreigns extras) results =
696712 File.writeBinary (Stuff.details root) $
697− Details.Details time outline (Map.foldrWithKey addNewLocal locals results) foreigns extras
713+ Details.Details time outline buildID (Map.foldrWithKey addNewLocal locals results) foreigns extras
698714
699715
700716addNewLocal :: ModuleName.Raw -> Result -> Map.Map ModuleName.Raw Details.Local -> Map.Map ModuleName.Raw Details.Local
@@ -702,7 +718,7 @@ addNewLocal name result locals =
702718 case result of
703719 RNew local _ _ _ -> Map.insert name local locals
704720 RSame local _ _ _ -> Map.insert name local locals
705− RCached _ _ -> locals
721+ RCached _ _ _ -> locals
706722 RNotFound _ -> locals
707723 RProblem _ -> locals
708724 RBlocked -> locals
@@ -731,7 +747,7 @@ addErrors result errors =
731747 case result of
732748 RNew _ _ _ _ -> errors
733749 RSame _ _ _ _ -> errors
734− RCached _ _ -> errors
750+ RCached _ _ _ -> errors
735751 RNotFound _ -> errors
736752 RProblem e -> e:errors
737753 RBlocked -> errors
@@ -744,7 +760,7 @@ addImportProblems results name problems =
744760 case results ! name of
745761 RNew _ _ _ _ -> problems
746762 RSame _ _ _ _ -> problems
747− RCached _ _ -> problems
763+ RCached _ _ _ -> problems
748764 RNotFound p -> (name, p) : problems
749765 RProblem _ -> problems
750766 RBlocked -> problems
@@ -802,7 +818,7 @@ toDocs result =
802818 case result of
803819 RNew _ _ _ d -> d
804820 RSame _ _ _ d -> d
805− RCached _ _ -> Nothing
821+ RCached _ _ _ -> Nothing
806822 RNotFound _ -> Nothing
807823 RProblem _ -> Nothing
808824 RBlocked -> Nothing
@@ -831,7 +847,7 @@ data ReplArtifacts =
831847fromRepl :: FilePath -> Details.Details -> B.ByteString -> IO (Either Exit.Repl ReplArtifacts)
832848fromRepl root details source =
833849 let
834− env@(Env _ _ pkg _ _ _) = makeEnv Reporting.ignorer root details
850+ env@(Env _ _ pkg _ _ _ _) = makeEnv Reporting.ignorer root details
835851 in
836852 case Parse.fromByteString pkg source of
837853 Left syntaxError ->
@@ -857,12 +873,12 @@ fromRepl root details source =
857873 putMVar rmvar resultMVars
858874 results <- traverse readMVar resultMVars
859875 writeDetails root details results
860− depsStatus <- checkDeps root resultMVars deps
876+ depsStatus <- checkDeps root resultMVars deps 0
861877 finalizeReplArtifacts env source modul depsStatus resultMVars results
862878
863879
864880finalizeReplArtifacts :: Env -> B.ByteString -> Src.Module -> DepsStatus -> ResultDict -> Map.Map ModuleName.Raw Result -> IO (Either Exit.Repl ReplArtifacts)
865−finalizeReplArtifacts env@(Env _ root pkg _ _ _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) depsStatus resultMVars results =
881+finalizeReplArtifacts env@(Env _ root pkg _ _ _ _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) depsStatus resultMVars results =
866882 let
867883 compileInput ifaces =
868884 case Compile.compile pkg ifaces modul of
@@ -958,7 +974,7 @@ findLocation env path =
958974
959975
960976findLoc :: Env -> FilePath -> FilePath -> IO (Either Exit.BuildProjectProblem Location)
961−findLoc (Env _ root _ srcDirs _ _) path absolutePath =
977+findLoc (Env _ root _ srcDirs _ _ _) path absolutePath =
962978 let
963979 (dirs, file) = FP.splitFileName absolutePath
964980 (final, ext) = FP.splitExtension file
@@ -1054,7 +1070,7 @@ data MainStatus
10541070
10551071
10561072crawlMain :: Env -> MVar StatusDict -> MainLocation -> IO MainStatus
1057−crawlMain env@(Env _ _ pkg _ _ _) mvar given =
1073+crawlMain env@(Env _ _ pkg _ buildID _ _) mvar given =
10581074 case given of
10591075 LInside name ->
10601076 do statusMVar <- newEmptyMVar
@@ -1069,7 +1085,7 @@ crawlMain env@(Env _ _ pkg _ _ _) mvar given =
10691085 case Parse.fromByteString pkg source of
10701086 Right modul@(Src.Module _ _ _ imports values _ _ _ _) ->
10711087 do let deps = map Src.getImportName imports
1072− let local = Details.Local path time deps (any isMain values)
1088+ let local = Details.Local path time deps (any isMain values) buildID buildID
10731089 crawlDeps env mvar deps (SOutsideOk local source modul)
10741090
10751091 Left syntaxError ->
@@ -1089,7 +1105,7 @@ data MainResult
10891105
10901106
10911107checkMain :: Env -> ResultDict -> MainStatus -> IO MainResult
1092−checkMain env@(Env _ root _ _ _ _) results pendingMain =
1108+checkMain env@(Env _ root _ _ _ _ _) results pendingMain =
10931109 case pendingMain of
10941110 SInside name ->
10951111 return (RInside name)
@@ -1097,8 +1113,8 @@ checkMain env@(Env _ root _ _ _ _) results pendingMain =
10971113 SOutsideErr err ->
10981114 return (ROutsideErr err)
10991115
1100− SOutsideOk local@(Details.Local path time deps _) source modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
1101− do depsStatus <- checkDeps root results deps
1116+ SOutsideOk local@(Details.Local path time deps _ _ lastCompile) source modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
1117+ do depsStatus <- checkDeps root results deps lastCompile
11021118 case depsStatus of
11031119 DepsChange ifaces ->
11041120 compileOutside env local source ifaces modul
@@ -1118,7 +1134,7 @@ checkMain env@(Env _ root _ _ _ _) results pendingMain =
11181134
11191135
11201136compileOutside :: Env -> Details.Local -> B.ByteString -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> IO MainResult
1121−compileOutside (Env key _ pkg _ _ _) (Details.Local path time _ _) source ifaces modul =
1137+compileOutside (Env key _ pkg _ _ _ _) (Details.Local path time _ _ _ _) source ifaces modul =
11221138 let
11231139 name = Src.getName modul
11241140 in
@@ -1141,7 +1157,7 @@ data Main
11411157
11421158
11431159toArtifacts :: Env -> Dependencies -> Map.Map ModuleName.Raw Result -> NE.List MainResult -> Either Exit.BuildProblem Artifacts
1144−toArtifacts (Env _ _ pkg _ _ _) foreigns results mainResults =
1160+toArtifacts (Env _ _ pkg _ _ _ _) foreigns results mainResults =
11451161 case gatherProblemsOrMains results mainResults of
11461162 Left (NE.List e es) ->
11471163 Left (Exit.BuildBadModules e es)
@@ -1178,7 +1194,7 @@ addInside name result modules =
11781194 case result of
11791195 RNew _ iface objs _ -> Fresh name iface objs : modules
11801196 RSame _ iface objs _ -> Fresh name iface objs : modules
1181− RCached main mvar -> Cached name main mvar : modules
1197+ RCached main _ mvar -> Cached name main mvar : modules
11821198 RNotFound _ -> error (badInside name)
11831199 RProblem _ -> error (badInside name)
11841200 RBlocked -> error (badInside name)