@@ -132,6 +132,9 @@ import qualified GHC as G
132
132
import GHC.Hs (LEpaComment )
133
133
import qualified GHC.Types.Error as Error
134
134
#endif
135
+ import qualified Control.Monad.Trans.State.Strict as S
136
+ import Data.Generics.Schemes
137
+ import Data.Generics.Aliases
135
138
136
139
-- | Given a string buffer, return the string (after preprocessing) and the 'ParsedModule'.
137
140
parseModule
@@ -380,12 +383,13 @@ mkHiFileResultNoCompile session tcm = do
380
383
pure $! mkHiFileResult ms mod_info (tmrRuntimeModules tcm)
381
384
382
385
mkHiFileResultCompile
383
- :: HscEnv
386
+ :: ShakeExtras
387
+ -> HscEnv
384
388
-> TcModuleResult
385
389
-> ModGuts
386
390
-> LinkableType -- ^ use object code or byte code?
387
391
-> IO (IdeResult HiFileResult )
388
- mkHiFileResultCompile session' tcm simplified_guts ltype = catchErrs $ do
392
+ mkHiFileResultCompile se session' tcm simplified_guts ltype = catchErrs $ do
389
393
let session = hscSetFlags (ms_hspp_opts ms) session'
390
394
ms = pm_mod_summary $ tmrParsed tcm
391
395
tcGblEnv = tmrTypechecked tcm
@@ -394,17 +398,17 @@ mkHiFileResultCompile session' tcm simplified_guts ltype = catchErrs $ do
394
398
ObjectLinkable -> generateObjectCode
395
399
BCOLinkable -> generateByteCode WriteCoreFile
396
400
397
- (linkable, details, diags) <-
401
+ (linkable, details, mguts, diags) <-
398
402
if mg_hsc_src simplified_guts == HsBootFile
399
403
then do
400
404
-- give variables unique OccNames
401
405
details <- mkBootModDetailsTc session tcGblEnv
402
- pure (Nothing , details, [] )
406
+ pure (Nothing , details, Nothing , [] )
403
407
else do
404
408
-- give variables unique OccNames
405
409
(guts, details) <- tidyProgram session simplified_guts
406
410
(diags, linkable) <- genLinkable session ms guts
407
- pure (linkable, details, diags)
411
+ pure (linkable, details, Just guts, diags)
408
412
#if MIN_VERSION_ghc(9,0,1)
409
413
let ! partial_iface = force (mkPartialIface session details simplified_guts)
410
414
final_iface <- mkFullIface session partial_iface Nothing
@@ -415,6 +419,51 @@ mkHiFileResultCompile session' tcm simplified_guts ltype = catchErrs $ do
415
419
(final_iface,_) <- mkIface session Nothing details simplified_guts
416
420
#endif
417
421
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
+
418
467
pure (diags, Just $! mkHiFileResult ms mod_info (tmrRuntimeModules tcm))
419
468
420
469
where
0 commit comments