Sorry for my fat fingers, I didn't intend to close.
One of the solutions I thought out after submitting this issue is that instances for Generically1
can be changed to derive Eq1 implementation through new class, e.g. GEq1
, which will have instances for whatever can go into Rep1
.
There's following instance for Generically1
(perhaps originally taken from the generic-data
package)
(Generic1 f, Eq1 (Rep1 f)) => Eq1 (Generically1 f)
The constraint Eq1 (Rep1 f)
is not satisfiable and never was because auxiliary Generics types like M1
(aka D1
in the error below) don't have Eq1
instance.
NB The same applies to Ord1
. Also there's no Show1
instance for Generically1
.
Take following program
#!/usr/bin/env cabal
{- cabal:
build-depends:
, base
default-language:
Haskell2010
ghc-options:
-main-is Test
-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE TypeApplications #-}
module Test (main) where
import Data.Functor.Classes
import GHC.Generics (Generic1, Generically1(..))
data I a = I [a] (Maybe a)
deriving stock (Eq, Ord, Show, Generic1)
deriving (Eq1) via (Generically1 I)
main :: IO ()
main = do
let x = I @Int [1, 2] (Just 3)
y = I @Int [] Nothing
putStrLn $ show $ eq1 x y
pure ()
And run it under GHC:
$ cabal run ./Test.hs
Created semaphore called cabal_semaphore_f with 32 slots.
/tmp/Test.hs:22:13: error: [GHC-39999]
• No instance for ‘Eq1
(GHC.Generics.D1
(GHC.Generics.MetaData
"I" "Test" "fake-package-0-inplace-script-Test.hs" False)
(GHC.Generics.C1
(GHC.Generics.MetaCons "I" GHC.Generics.PrefixI False)
(GHC.Generics.S1
(GHC.Generics.MetaSel
Nothing
GHC.Generics.NoSourceUnpackedness
GHC.Generics.NoSourceStrictness
GHC.Generics.DecidedLazy)
(GHC.Generics.Rec1 [])
GHC.Generics.:*: GHC.Generics.S1
(GHC.Generics.MetaSel
Nothing
GHC.Generics.NoSourceUnpackedness
GHC.Generics.NoSourceStrictness
GHC.Generics.DecidedLazy)
(GHC.Generics.Rec1 Maybe))))’
arising from the 'deriving' clause of a data type declaration
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Eq1 I)
|
22 | deriving (Eq1) via (Generically1 I)
| ^^^
Print False
, generally derive the Eq1
instance without errors.
Probably either the Eq1
instance for Generically1
should be removed since it doesn't work and never did or *1 instances for M1
and the rest should be added.
Optional:
There's following instance for Generically1
(perhaps originally taken from the generic-data
package)
(Generic1 f, Eq1 (Rep1 f)) => Eq1 (Generically1 f)
The constraint Eq1 (Rep1 f)
is not satisfiable and never was because auxiliary Generics types like M1
(aka D1
in the error below) don't have Eq1
instance.
NB The same applies to Ord1
. Also there's no Show1
instance for Generically1
.
Take following program
#!/usr/bin/env cabal
{- cabal:
build-depends:
, base
default-language:
Haskell2010
ghc-options:
-main-is Test
-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE TypeApplications #-}
module Test (main) where
import Data.Functor.Classes
import GHC.Generics (Generic1, Generically1(..))
data I a = I [a] (Maybe a)
deriving stock (Eq, Ord, Show, Generic1)
deriving (Eq1) via (Generically1 I)
main :: IO ()
main = do
let x = I @Int [1, 2] (Just 3)
y = I @Int [] Nothing
putStrLn $ show $ eq1 x y
pure ()
And run it under GHC:
$ cabal run ./Test.hs
Created semaphore called cabal_semaphore_f with 32 slots.
/tmp/Test.hs:22:13: error: [GHC-39999]
• No instance for ‘Eq1
(GHC.Generics.D1
(GHC.Generics.MetaData
"I" "Test" "fake-package-0-inplace-script-Test.hs" False)
(GHC.Generics.C1
(GHC.Generics.MetaCons "I" GHC.Generics.PrefixI False)
(GHC.Generics.S1
(GHC.Generics.MetaSel
Nothing
GHC.Generics.NoSourceUnpackedness
GHC.Generics.NoSourceStrictness
GHC.Generics.DecidedLazy)
(GHC.Generics.Rec1 [])
GHC.Generics.:*: GHC.Generics.S1
(GHC.Generics.MetaSel
Nothing
GHC.Generics.NoSourceUnpackedness
GHC.Generics.NoSourceStrictness
GHC.Generics.DecidedLazy)
(GHC.Generics.Rec1 Maybe))))’
arising from the 'deriving' clause of a data type declaration
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Eq1 I)
|
22 | deriving (Eq1) via (Generically1 I)
| ^^^
Print False
, generally derive the Eq1
instance without errors.
Probably either the Eq1
instance for Generically1
should be removed since it doesn't work and never did or *1 instances for M1
and the rest should be added.
Optional:
There's following instance for Generically1
(perhaps originally taken from the generic-data
package)
(Generic1 f, Eq1 (Rep1 f)) => Eq1 (Generically1 f)
The constraint Eq1 (Rep1 f)
is not satisfiable and never was because auxiliary Generics types like M1
(aka D1
in the error below) don't have Eq1
instance.
NB The same applies to Ord1
. Also there's no Show1
instance for Generically1
.
Take following program
#!/usr/bin/env cabal
{- cabal:
build-depends:
, base
default-language:
Haskell2010
ghc-options:
-main-is Test
-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE TypeApplications #-}
module Test (main) where
import Data.Functor.Classes
import GHC.Generics (Generic1, Generically1(..))
data I a = I [a] (Maybe a)
deriving stock (Eq, Ord, Show, Generic1)
deriving (Eq1) via (Generically1 I)
main :: IO ()
main = do
let x = I @Int [1, 2] (Just 3)
y = I @Int [] Nothing
putStrLn $ show $ eq1 x y
pure ()
And run it under GHC:
$ cabal run ./Test.hs
Created semaphore called cabal_semaphore_f with 32 slots.
/tmp/Test.hs:22:13: error: [GHC-39999]
• No instance for ‘Eq1
(GHC.Generics.D1
(GHC.Generics.MetaData
"I" "Test" "fake-package-0-inplace-script-Test.hs" False)
(GHC.Generics.C1
(GHC.Generics.MetaCons "I" GHC.Generics.PrefixI False)
(GHC.Generics.S1
(GHC.Generics.MetaSel
Nothing
GHC.Generics.NoSourceUnpackedness
GHC.Generics.NoSourceStrictness
GHC.Generics.DecidedLazy)
(GHC.Generics.Rec1 [])
GHC.Generics.:*: GHC.Generics.S1
(GHC.Generics.MetaSel
Nothing
GHC.Generics.NoSourceUnpackedness
GHC.Generics.NoSourceStrictness
GHC.Generics.DecidedLazy)
(GHC.Generics.Rec1 Maybe))))’
arising from the 'deriving' clause of a data type declaration
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Eq1 I)
|
22 | deriving (Eq1) via (Generically1 I)
| ^^^
Print False
, generally derive the Eq1
instance without errors.
Probably either the Eq1
instance for Generically1
should be removed since it doesn't work and never did or *1 instances for M1
and the rest should be added.
Optional:
Calling ghc directly to compile modules one by one with HPC enabled fails when TemplateHaskell is used and explicit destinations for resulting object and interface files are specified.
HereDoc.hs, a module with Template Haskell.
{-# OPTIONS_GHC -Wno-missing-fields #-}
module HereDoc (heredoc) where
import Language.Haskell.TH
import Language.Haskell.TH.Quote
heredoc :: QuasiQuoter
heredoc = QuasiQuoter
{ quoteExp = stringE . prepare
, quotePat = litP . stringL
}
where
prepare = filter (/= '\r')
Test.hs, main module.
{-# LANGUAGE QuasiQuotes #-}
module Test (main) where
import HereDoc
main :: IO ()
main = do
putStrLn [heredoc|Hello, World!|]
pure ()
Failing compilation:
$ ghc -fhpc -hpcdir hpc -c -O -osuf c_o -hisuf c_hi -o HereDoc.c_o -ohi HereDoc.c_hi HereDoc.hs
$ ghc -fhpc -hpcdir hpc -c -O -osuf c_o -hisuf c_hi -o Test.c_o -ohi Test.c_hi Test.hs -main-is Test
ghc-9.8.1.exe: | C:\home\tmp\windows-covererage-bug-report\HereDoc.c_o: unknown symbol `HereDoc_init__hpc'
ghc-9.8.1.exe: ^^ Could not load 'HereDoc_heredoc_closure', dependency unresolved. See top entry above.
GHC.ByteCode.Linker.lookupCE
During interactive linking, GHCi couldn't find the following symbol:
HereDoc_heredoc_closure
This may be due to you not asking GHCi to load extra object files,
archives or DLLs needed by your current session. Restart GHCi, specifying
the missing library using the -L/path/to/object/dir and -lmissinglibname
flags, or simply by naming the relevant files on the GHCi command line.
Alternatively, this link failure might indicate a bug in GHCi.
If you suspect the latter, please report this as a GHC bug:
https://www.haskell.org/ghc/reportabug
When I don't specify extensions and explicit files for .o
and .hi
files then it doesn't fail:
$ ghc -fhpc -hpcdir hpc -c -O HereDoc.hs
$ ghc -fhpc -hpcdir hpc -c -O Test.hs -main-is Test
$ l
HereDoc.hi HereDoc.hs HereDoc.o hpc/ Test.hi Test.hs* Test.o
$ ghc -package template-haskell -o Test.exe Test.o HereDoc.o
$ ./Test.exe
Hello, World!
This workaround is unsatisfactory because coverage object files are not interchageable with regular object files and thus ought to have different extension to tell them apart.
Successful compilation.
Optional:
The manual states that -fPIC is a no-op on Windows: https://downloads.haskell.org/ghc/latest/docs/users_guide/phases.html#ghc-flag--fPIC. It turns out that actually passing the flag has observable effect manifesting as an unexplained executable crash. The crash seems to only occur when underlying program uses a datatype with 6 constructors. Decreasing it to 5 makes program work with -fPIC.
test.cabal
cabal-version: 3.6
name:
test
version:
0.1
build-type:
Simple
flag pic
description:
-fPIC
default:
False
manual:
True
executable test
main-is:
Test.hs
build-depends:
, base
, optparse-applicative
ghc-options:
-main-is Test
if flag(pic)
ghc-options:
-fPIC
Test.hs
module Test (main) where
import Options.Applicative
import System.IO
data Command
= Command1
| Command2
| Command3
| Command4
| Command5
| Command6 -- Commenting this line works with -fPIC, uncommenting leads to a crash.
deriving (Show)
parseCommand :: Parser Command
parseCommand = pure Command2
main :: IO ()
main = do
putStrLn' "1"
cmd <- customExecParser (prefs mempty) $ info parseCommand mempty
putStrLn' "2"
putStrLn' $ "cmd = " ++ show cmd
pure ()
putStrLn' :: String -> IO ()
putStrLn' msg = putStrLn msg *> hFlush stdout
Successful run:
$ cabal run -c 'test -pic' test
Resolving dependencies...
Build profile: -w ghc-9.6.2 -O1
In order, the following will be built (use -v for more details):
- test-0.1 (exe:test) (configuration changed)
Configuring executable 'test' for test-0.1..
Preprocessing executable 'test' for test-0.1..
Building executable 'test' for test-0.1..
[1 of 1] Compiling Test [Flags changed]
[2 of 2] Linking c:\\home\\ghc-windows-bug\\dist-newstyle\\build\\x86_64-windows\\ghc-9.6.2\\test-0.1\\x\\test\\build\\test\\test.exe [Objects changed]
1
2
cmd = Command2
Failing run:
cabal run -c 'test +pic' test
Resolving dependencies...
Build profile: -w ghc-9.6.2 -O1
In order, the following will be built (use -v for more details):
- test-0.1 (exe:test) (configuration changed)
Configuring executable 'test' for test-0.1..
Preprocessing executable 'test' for test-0.1..
Building executable 'test' for test-0.1..
[1 of 1] Compiling Test [Flags changed]
[2 of 2] Linking c:\\home\\ghc-windows-bug\\dist-newstyle\\build\\x86_64-windows\\ghc-9.6.2\\test-0.1\\x\\test\\build\\test\\test.exe [Objects changed]
1
2
Access violation in generated code when executing data at 0x23f961770
Attempting to reconstruct a stack trace...
Frame Code address
* 0x2cd980 0x23f961770
* 0x2cd988 0x1
* 0x2cd990 0x4b4002cda68
* 0x2cd998 0x31790
Absence of unexpected crashes.
9.6.2
, 9.8.0.alpha4
Optional:
When enabling the ApplicativeDo
extension the provided program ceases to typecheck. It does work in 9.4.5 and does work if I move putStrLn
around or remove it entirely, which is surprising. Removing ApplicativeDo
extension also helps but I'd like to get its effects in parseCommandLine
function (omitted here for brevity).
Compile the following program.
Original program:
{-# LANGUAGE ApplicativeDo #-}
module Main (main) where
import Control.Monad
data Command
= PolyCmd
| VanillaCmd
data CommonConfig = CommonConfig
{ ccVerbose :: Bool
}
parseCommandline :: IO (CommonConfig, Command)
parseCommandline = undefined
locateHelper :: FilePath -> IO (Maybe FilePath)
locateHelper = undefined
complexWrapper :: IO a -> IO a
complexWrapper = undefined
vanillaRun :: IO ()
vanillaRun = pure ()
polyRun :: (forall a. IO a -> IO a) -> IO ()
polyRun f = f $ pure ()
main :: IO ()
main = do
(config, cmd) <- parseCommandline
when (ccVerbose config) $
putStrLn "OK"
let wrapper :: IO a -> IO a
wrapper act = do
complexWrapper act
case cmd of
VanillaCmd -> wrapper vanillaRun
PolyCmd -> polyRun wrapper
$ ghc -c Main.hs
Main.hs:42:27: error: [GHC-25897]
• Couldn't match type ‘a’ with ‘()’
Expected: IO a -> IO a
Actual: IO () -> IO ()
‘a’ is a rigid type variable bound by
a type expected by the context:
forall a. IO a -> IO a
at Main.hs:42:27-33
• In the first argument of ‘polyRun’, namely ‘wrapper’
In the expression: polyRun wrapper
In a case alternative: PolyCmd -> polyRun wrapper
|
42 | PolyCmd -> polyRun wrapper
| ^^^^^^^
However this one does typecheck
{-# LANGUAGE ApplicativeDo #-}
module Main (main) where
import Control.Monad
data Command
= PolyCmd
| VanillaCmd
data CommonConfig = CommonConfig
{ ccVerbose :: Bool
}
parseCommandline :: IO (CommonConfig, Command)
parseCommandline = undefined
locateHelper :: FilePath -> IO (Maybe FilePath)
locateHelper = undefined
complexWrapper :: IO a -> IO a
complexWrapper = undefined
vanillaRun :: IO ()
vanillaRun = pure ()
polyRun :: (forall a. IO a -> IO a) -> IO ()
polyRun f = f $ pure ()
main :: IO ()
main = do
(config, cmd) <- parseCommandline
let wrapper :: IO a -> IO a
wrapper act = do
when (ccVerbose config) $
putStrLn "OK"
complexWrapper act
case cmd of
VanillaCmd -> wrapper vanillaRun
PolyCmd -> polyRun wrapper
Commenting out ApplicativeDo
also makes the original program typecheck.
Original program typechecks successfully with ApplicativeDo
extension enabled.
Optional:
Fails with GHCs 9.6.2 and 9.4.5. Works with 9.2.8 though.
Resolving dependencies...
Build profile: -w ghc-9.6.2 -O1
In order, the following will be built (use -v for more details):
- haskhol-core-1.3.0 (lib) (configuration changed)
Warning: HaskHOL-Core.cabal:12:22: Packages with 'cabal-version: 1.12' or
later should specify a specific version of the Cabal spec of the form
'cabal-version: x.y'. Use 'cabal-version: 1.22'.
Configuring library for haskhol-core-1.3.0..
Preprocessing library for haskhol-core-1.3.0..
Building library for haskhol-core-1.3.0..
[ 4 of 24] Compiling HaskHOL.Core.Kernel.Types
<no location info>: error:
panic! (the 'impossible' happened)
GHC version 9.6.2:
lookupIdSubst
x_i8PE
InScope {wild_00 tyorda_a7l5 alphavars_a7l6 tyordas_a7l7
$dMonad_a7Yf $dMonadCatch_a7YB $dMonadThrow_a7YT $cvalidSubst_a8fp
$cvalidSubst_a8fE $cvalidSubst_a8fT $krep_a8ib $krep_a8ic
$krep_a8id $krep_a8ie $krep_a8if $krep_a8ig $krep_a8ih $krep_a8ii
$krep_a8ij $krep_a8ik $krep_a8il $krep_a8im $krep_a8in $krep_a8io
a_i8Ho ds_i8Hp a_i8WW $dEq_i8WX l1_i8WY tyAlphaOrder tyAConv
isVarType isType mkVarType destVarType destType tyVars catTyVars
typeSubst typeSubstFull typeTypeSubst tyBool tyBottom tyA tyB
destFunTy typeOf isTypeOpVar newPrimitiveTypeOp mkTypeOpVar
destTypeOp tyOpBool tyOpBottom tyOpFun tyApp typeOpVars
catTypeOpVars typeOpSubst typeOpInst isUType isSmall mkUType
mkUTypes uTypeFromTypeOpVar mkSmall destUType destUTypes
containsUType variantTyVar variantTyVars initTypeConstants
typeMatch $tcTypeSubst $tc'C:TypeSubst $fTypeSubstTypeOpHOLType
$fTypeSubstTypeOpTypeOp $fTypeSubstHOLTypeHOLType $mTyOpFun
$mTyOpBool $mTyB $mTyA $mTyFun $m:-> $mTyBool $trModule
$trModule_s8HR $trModule_s8HS $trModule_s8HT $trModule_s8HU
$krep_s8HV $krep_s8HW $krep_s8HX $krep_s8HY $krep_s8HZ
$tcTypeSubst_s8I0 $tcTypeSubst_s8I1 $krep_s8I2 $krep_s8I3
$tc'C:TypeSubst_s8I4 $tc'C:TypeSubst_s8I5 tyOpFun_s8IS tyOpFun_s8IT
tyOpBottom_s8Ja tyOpBottom_s8Jb tyOpBool_s8Jc tyOpBool_s8Jd
tyB_s8LQ tyA_s8LR catTypeOpVars_s8Xb}
Call stack:
CallStack (from HasCallStack):
callStackDoc, called at compiler/GHC/Utils/Panic.hs:189:37 in ghc:GHC.Utils.Panic
pprPanic, called at compiler/GHC/Core/Subst.hs:197:17 in ghc:GHC.Core.Subst
CallStack (from HasCallStack):
panic, called at compiler/GHC/Utils/Error.hs:454:29 in ghc:GHC.Utils.Error
Please report this as a GHC bug: https://www.haskell.org/ghc/reportabug
Error: cabal: Failed to build haskhol-core-1.3.0.
Download from github as Hackage version is likely outdated.
git clone https://github.com/ecaustin/haskhol-core
cd haskhol-core
cabal build
Package builds without internal errors. May fail to build due to real errors though, haven't checked fully.
9.6.2, 9.4.5
Forgot the attachment ghc-crash.tar.gz.
Using ghc to evaluate a function that uses linear types and imports linearly-typed helper from another module leads to segmentation fault. Moving helper over to current module removes the problem.
After messing with cabal repl -v3
and extracting ghc command I got following stack trace in gdb (this one is for bigger project though but I believe the underlying issue is the same)
Thread 13 "ghc_worker" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffc902f6c0 (LWP 1182129)]
0x00007fffef193a38 in interpretBCO ()
from /nix/store/8lkbri2blncc4vh4rjqfc47jdx3qd434-ghc-native-bignum-9.6.1/lib/ghc-9.6.1/bin/../lib/x86_64-linux-ghc-9.6.1/libHSrts-1.0.2_thr-ghc9.6.1.so
(gdb) where
#0 0x00007fffef193a38 in interpretBCO ()
from /nix/store/8lkbri2blncc4vh4rjqfc47jdx3qd434-ghc-native-bignum-9.6.1/lib/ghc-9.6.1/bin/../lib/x86_64-linux-ghc-9.6.1/libHSrts-1.0.2_thr-ghc9.6.1.so
#1 0x00007fffef1a232d in schedule ()
from /nix/store/8lkbri2blncc4vh4rjqfc47jdx3qd434-ghc-native-bignum-9.6.1/lib/ghc-9.6.1/bin/../lib/x86_64-linux-ghc-9.6.1/libHSrts-1.0.2_thr-ghc9.6.1.so
#2 0x00007fffef1a288c in scheduleWorker ()
from /nix/store/8lkbri2blncc4vh4rjqfc47jdx3qd434-ghc-native-bignum-9.6.1/lib/ghc-9.6.1/bin/../lib/x86_64-linux-ghc-9.6.1/libHSrts-1.0.2_thr-ghc9.6.1.so
#3 0x00007fffef1a6f0d in workerStart ()
from /nix/store/8lkbri2blncc4vh4rjqfc47jdx3qd434-ghc-native-bignum-9.6.1/lib/ghc-9.6.1/bin/../lib/x86_64-linux-ghc-9.6.1/libHSrts-1.0.2_thr-ghc9.6.1.so
#4 0x00007fffeef7fe24 in start_thread () from /nix/store/1n2l5law9g3b77hcfyp50vrhhssbrj5g-glibc-2.37-8/lib/libc.so.6
#5 0x00007fffef0019b0 in clone3 () from /nix/store/1n2l5law9g3b77hcfyp50vrhhssbrj5g-glibc-2.37-8/lib/libc.so.6
tar xvf ghc-crash.tar.gz
cabal repl
$ cabal repl ghc-crash:lib:ghc-crash --repl-no-load --repl-option -ghci-script=ghc-script.txt
Resolving dependencies...
Build profile: -w ghc-9.6.1 -O1
In order, the following will be built (use -v for more details):
- ghc-crash-0.1 (lib) (first run)
Configuring library for ghc-crash-0.1..
Preprocessing library for ghc-crash-0.1..
GHCi, version 9.6.1: https://www.haskell.org/ghc/ :? for help
<no location info>: warning: [GHC-32850] [-Wmissing-home-modules]
These modules are needed for compilation but not listed in your .cabal file's other-modules for ‘ghc-crash-0.1-inplace’ :
TextFold
[1 of 2] Compiling TextFold
[2 of 2] Compiling GhcCrash
Ok, two modules loaded.
"Error: cabal: repl failed for ghc-crash-0.1. The build process segfaulted
(i.e. SIGSEGV).
Literal sources for reference and ease of inspection:
ghc-script.txt
:load GhcCrash.hs
:set -XOverloadedStrings
fileGlobsToRegex ["foo", "bar"]
GhcCrash.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module GhcCrash (fileGlobsToRegex) where
import Data.Text (Text)
import Data.Text.Builder.Linear.Buffer
-- Fails when imported, works if module is inlined in this one.
import TextFold
fileGlobsToRegex :: [Text] -> Text
fileGlobsToRegex patterns = runBuffer initRe
where
initRe :: Buffer %1 -> Buffer
initRe buf =
mkRe patterns (buf |>. '^') |>. '$'
mkRe :: [Text] -> Buffer %1 -> Buffer
mkRe [] buf = buf
mkRe (x : xs) buf =
mkRe' xs ((textFoldLinear f buf x))
mkRe' :: [Text] -> Buffer %1 -> Buffer
mkRe' [] buf = buf
mkRe' (x : xs) buf =
mkRe' xs ((textFoldLinear f (buf |>. '|') x))
f :: Char -> Buffer %1 -> Buffer
f c buf = case c of
'*' -> buf |> ".*"
other -> buf |>. other
TextFold.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module TextFold (textFoldLinear) where
import Data.Text (Text)
import Data.Text.Internal qualified as TI
import Data.Text.Unsafe qualified as TU
import GHC.Exts (UnliftedType)
{-# INLINE textFoldLinear #-}
textFoldLinear :: forall (a :: UnliftedType). (Char -> a %1 -> a) -> a %1 -> Text -> a
textFoldLinear f seed (TI.Text arr off len) = textFoldLinearLoop seed 0 off
where
!end = off + len
textFoldLinearLoop :: a %1 -> Int -> Int -> a
textFoldLinearLoop x !i !j
| j >= end = x
| otherwise =
let TU.Iter c delta = TU.iterArray arr j
in textFoldLinearLoop (f c x) (i + 1) (j + delta)
ghc-crash.cabal
cabal-version: 3.6
name: ghc-crash
version: 0.1
build-type:
Simple
common ghc-options
default-language:
GHC2021
default-extensions:
LambdaCase
ghc-options:
-Weverything
-Wno-all-missed-specialisations
-Wno-implicit-prelude
-Wno-missed-specialisations
-Wno-missing-import-lists
-Wno-missing-local-signatures
-Wno-missing-safe-haskell-mode
-Wno-safe
-Wno-type-defaults
-Wno-unsafe
if impl(ghc >= 8.8)
ghc-options:
-Wno-missing-deriving-strategies
if impl(ghc >= 9.2)
ghc-options:
-Wno-missing-kind-signatures
library
import: ghc-options
exposed-modules:
GhcCrash
TextFold
hs-source-dirs:
.
build-depends:
, base >= 4.16
, text
, text-builder-linear
No segmentation fault, ghci outputs ^foo|bar$
.
Using functions that ultimately desugar into unsafeFreezeArray#
without doing copy beforehand leads to crash.
Clone https://github.com/sergv/array-freeze-bug and do cabal run array-freeze
. If recent enough nix with flakes support is available then do nix develop -c cabal run array-freeze
.
Otherwise consider program:
#!/usr/bin/env cabal
{- cabal:
build-depends:
, base
, primitive
, vector
-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main (main) where
import Control.Exception
import Control.Monad.Primitive
import Data.Char
import Data.List qualified as L
import Data.Traversable
import Data.Vector qualified as V
import Data.Vector.Mutable qualified as VM
import Data.Vector.Unboxed qualified as U
{-# NOINLINE process #-}
process
:: V.MVector (PrimState IO) (U.Vector Int)
-> [U.Vector Int]
-> V.Vector Int
-> IO Int
process store haystacks needle = do
fmap L.minimum $ for haystacks $ \haystack -> do
V.iforM_ needle $ \idx i -> do
VM.write store idx (U.slice i 5 haystack)
-- -- GOOD
-- store' <- V.freeze store
-- BAD
store' <- V.unsafeFreeze store
evaluate $ processOne store' 0
{-# NOINLINE processOne #-}
processOne
:: V.Vector (U.Vector Int)
-> Int
-> Int
processOne !items !acc
| V.null items
= acc
| otherwise
= let !curr = V.head items
in processOne (V.tail items) $! (acc `max` U.head curr + 1)
main :: IO ()
main = do
let n :: Int
n = 10000
let haystacks :: [U.Vector Int]
haystacks =
map (U.fromList . map ord) $ map (\k -> "abcdefghijklmnopqrstuvwxyz" ++ show k) [1..n]
needle :: V.Vector Int
needle = V.fromList [1..10]
!res <- do
store <- VM.new (V.length needle)
process store haystacks needle
putStrLn $ "res = " ++ show res
pure ()
It can either be built with cabal file present in the git repository or run as standalone cabal script like this: cabal ./Main.hs
.
In any of outlined scenarios of running the reproduction example the expectation is that program prints a number.
What actually happens is that the program ends with segmentation fault.
If unsafeFreeze
in replaced by vanilla freeze
then program works and prints 108. The intention is to avoid copies by employing unsafeFreeze
onto reusable mutable store that gets allocated only once outside of a processing loop.
For convenience the git repsitory includes results of dumping core on GHC 9.4.2. The version that fails: https://github.com/sergv/array-freeze-bug/blob/master/Main.bad.dump-simpl and the version that works: https://github.com/sergv/array-freeze-bug/blob/master/Main.good.dump-simpl. The difference between the two (https://github.com/sergv/array-freeze-bug/blob/master/Main.dump-simpl.diff) comes to calling unsafeArrayFreeze#
vs doing a copy.
Extensive investigation in a bigger program where this problem initially occured suggests that argument of processOne
becomes invalid after some iterations and at one point just contains junk vectors (maybe due to GC, haven't conclusively established that).
Perhaps I'm just missing something about unsafeFrezeArray#
's semantics but its docs are pretty sparse and it seems its return value shoud be valid as long as its argument is kept around.
Optional:
Sure, if there are no type variables then adding a constraint like Foo Int
is a misleading suggestion.
If the function we're considering only takes argumenst of concrete types then I think no suggestion should be produced.
However if the constraint includes a polymorphic type variable (like Foo Int (Quux a)
) and a function takes polymorphic argument (like a
) and GHC determined that it's the type a
that should be constrained, then my hunch is that the user rather wants to consrain the polymorphic argument than define an instance for arbitrary type (instance Foo Int (Quux c)
).
so unless we suggest both there's a danger of misleading the user.
But isn't 'adding (Foo Int (Quux a))
to the type signature' a valid fix in either case? If ultimately the instance doesn't exist then the user will get an error later on when calling the function. The error message states that it's a possible fix after all, thus cautioning that it may deviate from the user's intentions.
When a user didn't specify typeclass constraints for all variables in a function signature the GHC sometimes suggests to add relevant constraint to the signature, like this:
• No instance for (Foo a) arising from a use of ‘foo’
Possible fix:
add (Foo a) to the context of
the type signature for:
bar :: forall a. a -> Sum a
However if the constraint is a "non-trivial" one, in particular if it uses multiparameter typeclass and some of the parameters not variables then the suggestion is not produced. My expectation is that suggestion should be produced.
A bit of context, the Haskell Language Server uses GHC's error messages to suggest fixes. When error message contains the Possible fix
similar to the one shows before then in can add the constraint to the type signature automatically as a code action. But if the suggestion is missing then it's just not possible. It appears that only GHC has all the necessary info regarding whether to produce Possible fix
or not so the issue cannot be worked around in HLS (nor should it be since GHC's error messages are useful even for users that don't use HLS).
For the following program the suggestion is not produced:
{-# LANGUAGE MultiParamTypeClasses #-}
import Data.Kind
import Data.Monoid
class Foo (a :: Type) (b :: Type) where
foo :: Monoid m => (a -> m) -> b -> m
bar :: a -> Sum Int
bar x = foo Sum x
/tmp/test2.hs:10:9: error:
• No instance for (Foo Int a) arising from a use of ‘foo’
• In the expression: foo Sum x
In an equation for ‘bar’: bar x = foo Sum x
|
10 | bar x = foo Sum x
| ^^^
But for a slightly simpler program the suggestion is present
{-# LANGUAGE MultiParamTypeClasses #-}
import Data.Kind
import Data.Monoid
class Foo (a :: Type) where
foo :: Monoid m => (a -> m) -> a -> m
bar :: a -> Sum a
bar x = foo Sum x
/tmp/test2.hs:10:9: error:
• No instance for (Foo a) arising from a use of ‘foo’
Possible fix:
add (Foo a) to the context of
the type signature for:
bar :: forall a. a -> Sum a
• In the expression: foo Sum x
In an equation for ‘bar’: bar x = foo Sum x
|
10 | bar x = foo Sum x
| ^^^
I found out that call to isTyVarClassPred
at https://gitlab.haskell.org/ghc/ghc/-/blob/master/compiler/GHC/Tc/Errors/Ppr.hs#L2844 is responsible for GHC's decision to omit the suggestion. The call appears to check that typeclass is only applied to variables and thus fails for a constraint like Foo Int a
which has constants mixed in.
Perhaps the check should be relaxed to require that constraint to be suggested has some variables in its parameters? Or maybe the check shouldn't be performed at all (not really sure about this one though)?
One thing to probably watch out for is that the variable can occur as part of some other type in the constraint as illustrated by following modification to the program
{-# LANGUAGE MultiParamTypeClasses #-}
import Data.Kind
import Data.Monoid
class Foo (a :: Type) (b :: Type) where
foo :: Monoid m => (a -> m) -> b -> m
newtype Quux a = Quux { unQuux :: a }
bar :: a -> Sum Int
bar x = foo Sum (Quux x)
/tmp/test2.hs:12:9: error:
• No instance for (Foo Int (Quux a)) arising from a use of ‘foo’
• In the expression: foo Sum (Quux x)
In an equation for ‘bar’: bar x = foo Sum (Quux x)
|
12 | bar x = foo Sum (Quux x)
| ^^^
NB if I just omit the call to isTyVarClassPred
the patched ghc produces the error message I was expecting all along:
• No instance for (Foo Int (Quux a)) arising from a use of ‘foo’
Possible fix:
add (Foo Int (Quux a)) to the context of
the type signature for:
bar :: forall a. a -> Sum Int
• In the expression: foo Sum (Quux x)
In an equation for ‘bar’: bar x = foo Sum (Quux x)
|
12 | bar x = foo Sum (Quux x)
| ^^^
Optional:
As summarized in #20907, ld.lld --version
produces a string that does not start with LLD
and thus GHC is unable to detect it.
@mpickering perhaps this PR could be merged after the mold one got put on hold?
As summarized in #20907, ld.lld --version
produces a string that does not start with LLD
and thus GHC is unable to detect it.
On Debian testing lld version 13 changed output of --version
and ghc's ./configure
script is unable to detect it. This affects both building development version of ghc and already released ghcs which use ./configure
to detect platform capabilities.
Namely, the output of ld.lld --version
is now
Debian LLD 13.0.0 (compatible with GNU linkers)
But GHC's detection only recognizes lld if its --version
starts with LLD
string.
I haven't investigated much of why the string changed, either this is a new capability in recent versions of lld (available via defining LLD_VENDOR when building llvm tools (which Debian does), cf https://github.com/llvm/llvm-project/blob/main/lld/Common/Version.cpp#L26) or an old capability which Debian recently started using. However it's clear that it may be used and in general the output of --version
may not start with the LLD
string.
ld.lld --version
doesn't start with LLD
, see abovSee attached log.txt
for output of configure
and ghc --info
both witnessing that ld.lld
was not picked up: log.txt
Expected to get ghc that will use ld.lld
linker.
Got ghc that uses ld.gold
linker even thout I have ld.lld
linker available. It's self-reported version is 13
which ghc claims to be compatible with.
The configure
scirpt produces following when trying to detect ld.lld
:
checking for ld.lld... ld.lld
configure: unknown linker version Debian LLD 13.0.0 (compatible with GNU linkers)
configure: unable to convince 'gcc' to use linker 'ld.lld'
checking for -ld.gold... no
checking for ld.gold... ld.gold
checking whether C compiler supports -fuse-ld=gold... yes
Not sure it's worth to change detection for ld
that was working before now that mold
is detected separately.
Well, I'm not 100% sure what compatibility means in this case. FWIW gold doesn't have --hash-size
and --reduce-memory-overheads
flags either, same for lld
. In a similar vain, lld
claims to be "compatible":
$ ld.lld --version
Debian LLD 13.0.0 (compatible with GNU linkers)
I guess by compatibility they mean that a linker can link an executable if one of the GNU linkers can. Or that even parts of build (e.g. .a
libraries) can be linked with one linker while others with another one and the claim is that end result would run OK.
I'd guess that mold
is not a drop-in replacement for ld
if ld
-specific flags are used. If no flags are used then it looks like it may very well be a drop-in replacement. Ditto for gold
and lld
which have their own set of flags and wouldn't work with --hash-size
and --reduce-memory-overheads
.
Overall it looks like mold
is closer to gold
than to ld
flagwise from ghc's perspective.