@@ -132,6 +132,9 @@ import qualified GHC as G
132132import GHC.Hs (LEpaComment )
133133import qualified GHC.Types.Error as Error
134134#endif
135+ import qualified Control.Monad.Trans.State.Strict as S
136+ import Data.Generics.Schemes
137+ import Data.Generics.Aliases
135138
136139-- | Given a string buffer, return the string (after preprocessing) and the 'ParsedModule'.
137140parseModule
@@ -380,12 +383,13 @@ mkHiFileResultNoCompile session tcm = do
380383 pure $! mkHiFileResult ms mod_info (tmrRuntimeModules tcm)
381384
382385mkHiFileResultCompile
383- :: HscEnv
386+ :: ShakeExtras
387+ -> HscEnv
384388 -> TcModuleResult
385389 -> ModGuts
386390 -> LinkableType -- ^ use object code or byte code?
387391 -> IO (IdeResult HiFileResult )
388- mkHiFileResultCompile session' tcm simplified_guts ltype = catchErrs $ do
392+ mkHiFileResultCompile se session' tcm simplified_guts ltype = catchErrs $ do
389393 let session = hscSetFlags (ms_hspp_opts ms) session'
390394 ms = pm_mod_summary $ tmrParsed tcm
391395 tcGblEnv = tmrTypechecked tcm
@@ -394,17 +398,17 @@ mkHiFileResultCompile session' tcm simplified_guts ltype = catchErrs $ do
394398 ObjectLinkable -> generateObjectCode
395399 BCOLinkable -> generateByteCode WriteCoreFile
396400
397- (linkable, details, diags) <-
401+ (linkable, details, mguts, diags) <-
398402 if mg_hsc_src simplified_guts == HsBootFile
399403 then do
400404 -- give variables unique OccNames
401405 details <- mkBootModDetailsTc session tcGblEnv
402- pure (Nothing , details, [] )
406+ pure (Nothing , details, Nothing , [] )
403407 else do
404408 -- give variables unique OccNames
405409 (guts, details) <- tidyProgram session simplified_guts
406410 (diags, linkable) <- genLinkable session ms guts
407- pure (linkable, details, diags)
411+ pure (linkable, details, Just guts, diags)
408412#if MIN_VERSION_ghc(9,0,1)
409413 let ! partial_iface = force (mkPartialIface session details simplified_guts)
410414 final_iface <- mkFullIface session partial_iface Nothing
@@ -415,6 +419,51 @@ mkHiFileResultCompile session' tcm simplified_guts ltype = catchErrs $ do
415419 (final_iface,_) <- mkIface session Nothing details simplified_guts
416420#endif
417421 let mod_info = HomeModInfo final_iface details linkable
422+
423+ -- Verify core file by rountrip testing and comparison
424+ IdeOptions {optVerifyCoreFile} <- getIdeOptionsIO se
425+ when (maybe False (not . isObjectLinkable) linkable && optVerifyCoreFile) $ do
426+ let core_fp = ml_core_file $ ms_location ms
427+ traceIO $ " Verifying " ++ core_fp
428+ core <- readBinCoreFile (mkUpdater $ hsc_NC session) core_fp
429+ let CgGuts {cg_binds = unprep_binds, cg_tycons = tycons } = case mguts of
430+ Nothing -> error " invariant optVerifyCoreFile: guts must exist if linkable exists)"
431+ Just g -> g
432+ mod = ms_mod ms
433+ data_tycons = filter isDataTyCon tycons
434+ CgGuts {cg_binds = unprep_binds'} <- coreFileToCgGuts session final_iface details core
435+
436+ -- Run corePrep first as we want to test the final version of the program that will
437+ -- get translated to STG/Bytecode
438+ (prepd_binds , _) <- corePrepPgm session mod (ms_location ms) unprep_binds data_tycons
439+ (prepd_binds', _) <- corePrepPgm session mod (ms_location ms) unprep_binds' data_tycons
440+ let binds = noUnfoldings $ (map flattenBinds . (: [] )) $ prepd_binds
441+ binds' = noUnfoldings $ (map flattenBinds . (: [] )) $ prepd_binds'
442+
443+ -- diffBinds is unreliable, sometimes it goes down the wrong track.
444+ -- This fixes the order of the bindings so that it is less likely to do so.
445+ diffs2 = concat $ flip S. evalState (mkRnEnv2 emptyInScopeSet) $ zipWithM go binds binds'
446+ -- diffs1 = concat $ flip S.evalState (mkRnEnv2 emptyInScopeSet) $ zipWithM go (map (:[]) $ concat binds) (map (:[]) $ concat binds')
447+ -- diffs3 = flip S.evalState (mkRnEnv2 emptyInScopeSet) $ go (concat binds) (concat binds')
448+
449+ diffs = diffs2
450+ go x y = S. state $ \ s -> diffBinds True s x y
451+
452+ -- The roundtrip doesn't preserver OtherUnfolding or occInfo, but neither are of these
453+ -- are used for generate core or bytecode, so we can safely ignore them
454+ -- SYB is slow but fine given that this is only used for testing
455+ noUnfoldings = everywhere $ mkT $ \ v -> if isId v
456+ then
457+ let v' = if isOtherUnfolding (realIdUnfolding v) then (setIdUnfolding v noUnfolding) else v
458+ in setIdOccInfo v' noOccInfo
459+ else v
460+ isOtherUnfolding (OtherCon _) = True
461+ isOtherUnfolding _ = False
462+
463+
464+ when (not $ null diffs) $
465+ panicDoc " verify core failed!" (vcat $ punctuate (text " \n\n " ) (diffs )) -- ++ [ppr binds , ppr binds']))
466+
418467 pure (diags, Just $! mkHiFileResult ms mod_info (tmrRuntimeModules tcm))
419468
420469 where
0 commit comments