GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2021-08-02T17:29:55Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/16404Type error recovery crash2021-08-02T17:29:55ZSimon Peyton JonesType error recovery crashThis program is derived from #16376:
```
{-# LANGUAGE TypeApplications #-}
module Bug where
h x = let f = id @Maybe
in Just f
```
If you compile with `-fdefer-type-errors -dcore-lint` you'll get
```
*** Core Lint errors : in re...This program is derived from #16376:
```
{-# LANGUAGE TypeApplications #-}
module Bug where
h x = let f = id @Maybe
in Just f
```
If you compile with `-fdefer-type-errors -dcore-lint` you'll get
```
*** Core Lint errors : in result of Desugar (before optimization) ***
<no location info>: warning:
In the expression: f_arZ @ a_at1
Out of scope: f_arZ :: forall a. a
[LclId]
*** Offending Program ***
Rec {
$trModule :: Module
[LclIdX]
$trModule = Module (TrNameS "main"#) (TrNameS "T16376"#)
h :: forall p a. p -> Maybe a
[LclIdX]
h = \ (@ p_asV) (@ a_at1) ->
case typeError
@ ('TupleRep '[])
@ ((* -> *) ~# *)
"T16376.hs:4:19: error:\n\
\ \\226\\128\\162 Expecting one more argument to \\226\\128\\152Maybe\\226\\128\\153\n\
\ Expected a type, but \\226\\128\\152Maybe\\226\\128\\153 has kind \\226\\128\\152* -> *\\226\\128\\153\n\
\ \\226\\128\\162 In the type \\226\\128\\152Maybe\\226\\128\\153\n\
\ In the expression: id @Maybe\n\
\ In an equation for \\226\\128\\152f\\226\\128\\153: f = id @Maybe\n\
\(deferred type error)"#
of co_asZ
{ __DEFAULT ->
letrec {
h_at5 :: p_asV -> Maybe a_at1
[LclId]
h_at5 = \ (x_arY :: p_asV) -> Just @ a_at1 (f_arZ @ a_at1); } in
h_at5
}
end Rec }
```
Without Lint it just squeezes by, because that \`case typeError of ..." discards the "..." since it is unreachablehttps://gitlab.haskell.org/ghc/ghc/-/issues/16403Add isBinDigit to Data.Char2020-06-26T05:27:42ZhesiodAdd isBinDigit to Data.CharThe `Data.Char` module contains helper functions that determine whether a Char is a decimal, octal or hexadecimal digit (`isDigit`, `isOctDigit`, `isHexDigit`). A similar helper function for binary digits is not included for no apparent ...The `Data.Char` module contains helper functions that determine whether a Char is a decimal, octal or hexadecimal digit (`isDigit`, `isOctDigit`, `isHexDigit`). A similar helper function for binary digits is not included for no apparent reason (maybe because the number parsers in the `Numeric` module also don't support binary digits?).
The implementation for such a `isBinDigit` should be trivial, aside from performance considerations: `isDigit` and friends perform the test using only subtraction and an unsigned comparison, I'm not sure whether `isBinDigit` offers any different performant implementations.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.6.4 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Add isBinDigit to Data.Char","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.4","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"The {{{Data.Char}}} module contains helper functions that determine whether a Char is a decimal, octal or hexadecimal digit ({{{isDigit}}}, {{{isOctDigit}}}, {{{isHexDigit}}}). A similar helper function for binary digits is not included for no apparent reason (maybe because the number parsers in the {{{Numeric}}} module also don't support binary digits?).\r\n\r\nThe implementation for such a {{{isBinDigit}}} should be trivial, aside from performance considerations: {{{isDigit}}} and friends perform the test using only subtraction and an unsigned comparison, I'm not sure whether {{{isBinDigit}}} offers any different performant implementations.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16402GHC doesnt' notice that `narrowWordFOO (x .&. (2^FOO-1))` is just `narrowWord...2022-03-03T09:07:12ZMateusz KowalczykGHC doesnt' notice that `narrowWordFOO (x .&. (2^FOO-1))` is just `narrowWordFOO x`.```hs
{-# OPTIONS_GHC -ddump-simpl -ddump-to-file -dhex-word-literals -O2 #-}
{-# LANGUAGE TypeApplications #-}
module NarrowWord where
import Data.Word
import Data.Bits
smallWord_foo :: Word64 -> Word64
smallWord_foo x = fromIntegral...```hs
{-# OPTIONS_GHC -ddump-simpl -ddump-to-file -dhex-word-literals -O2 #-}
{-# LANGUAGE TypeApplications #-}
module NarrowWord where
import Data.Word
import Data.Bits
smallWord_foo :: Word64 -> Word64
smallWord_foo x = fromIntegral @Word16 $ fromIntegral (x .&. 0xFFFF)
smallWord_bar :: Word64 -> Word64
smallWord_bar x = fromIntegral @Word16 $ fromIntegral x
test :: Bool
test =
let w = 72430412501
in smallWord_foo w == smallWord_bar w
```
```hs
-- RHS size: {terms: 7, types: 3, coercions: 0, joins: 0/0}
smallWord_bar :: Word64 -> Word64
[GblId,
Arity=1,
Caf=NoCafRefs,
Str=<S(S),1*U(U)>m,
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
Tmpl= \ (x_a1so [Occ=Once!] :: Word64) ->
case x_a1so of { GHC.Word.W64# x#_a2Mw [Occ=Once] ->
GHC.Word.W64# (GHC.Prim.narrow16Word# x#_a2Mw)
}}]
smallWord_bar
= \ (x_a1so :: Word64) ->
case x_a1so of { GHC.Word.W64# x#_a2Mw ->
GHC.Word.W64# (GHC.Prim.narrow16Word# x#_a2Mw)
}
-- RHS size: {terms: 9, types: 3, coercions: 0, joins: 0/0}
smallWord_foo :: Word64 -> Word64
[GblId,
Arity=1,
Caf=NoCafRefs,
Str=<S(S),1*U(U)>m,
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
Tmpl= \ (x_a1hU [Occ=Once!] :: Word64) ->
case x_a1hU of { GHC.Word.W64# x#_a30a [Occ=Once] ->
GHC.Word.W64#
(GHC.Prim.narrow16Word# (GHC.Prim.and# x#_a30a 0xffff##))
}}]
smallWord_foo
= \ (x_a1hU :: Word64) ->
case x_a1hU of { GHC.Word.W64# x#_a30a ->
GHC.Word.W64#
(GHC.Prim.narrow16Word# (GHC.Prim.and# x#_a30a 0xffff##))
}
-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
test :: Bool
[GblId,
Caf=NoCafRefs,
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)
Tmpl= GHC.Types.True}]
test = GHC.Types.True
```
For Word8, Word16, Word32, Word64 and Int8, Int16, Int32, Int64, I would expect GHC to never produce the `and`.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHC doesnt' notice that (narrowWordFOO (x .&. FOO)) is just `x`.","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"{{{#!hs\r\n{-# OPTIONS_GHC -ddump-simpl -ddump-to-file -dhex-word-literals -O2 #-}\r\n{-# LANGUAGE TypeApplications #-}\r\nmodule NarrowWord where\r\n\r\nimport Data.Word\r\nimport Data.Bits\r\n\r\n\r\nsmallWord_foo :: Word64 -> Word64\r\nsmallWord_foo x = fromIntegral @Word16 $ fromIntegral (x .&. 0xFFFF)\r\n\r\nsmallWord_bar :: Word64 -> Word64\r\nsmallWord_bar x = fromIntegral @Word16 $ fromIntegral x\r\n\r\ntest :: Bool\r\ntest =\r\n let w = 72430412501\r\n in smallWord_foo w == smallWord_bar w\r\n}}}\r\n\r\n{{{#!hs\r\n-- RHS size: {terms: 7, types: 3, coercions: 0, joins: 0/0}\r\nsmallWord_bar :: Word64 -> Word64\r\n[GblId,\r\n Arity=1,\r\n Caf=NoCafRefs,\r\n Str=<S(S),1*U(U)>m,\r\n Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,\r\n WorkFree=True, Expandable=True,\r\n Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)\r\n Tmpl= \\ (x_a1so [Occ=Once!] :: Word64) ->\r\n case x_a1so of { GHC.Word.W64# x#_a2Mw [Occ=Once] ->\r\n GHC.Word.W64# (GHC.Prim.narrow16Word# x#_a2Mw)\r\n }}]\r\nsmallWord_bar\r\n = \\ (x_a1so :: Word64) ->\r\n case x_a1so of { GHC.Word.W64# x#_a2Mw ->\r\n GHC.Word.W64# (GHC.Prim.narrow16Word# x#_a2Mw)\r\n }\r\n\r\n-- RHS size: {terms: 9, types: 3, coercions: 0, joins: 0/0}\r\nsmallWord_foo :: Word64 -> Word64\r\n[GblId,\r\n Arity=1,\r\n Caf=NoCafRefs,\r\n Str=<S(S),1*U(U)>m,\r\n Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,\r\n WorkFree=True, Expandable=True,\r\n Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)\r\n Tmpl= \\ (x_a1hU [Occ=Once!] :: Word64) ->\r\n case x_a1hU of { GHC.Word.W64# x#_a30a [Occ=Once] ->\r\n GHC.Word.W64#\r\n (GHC.Prim.narrow16Word# (GHC.Prim.and# x#_a30a 0xffff##))\r\n }}]\r\nsmallWord_foo\r\n = \\ (x_a1hU :: Word64) ->\r\n case x_a1hU of { GHC.Word.W64# x#_a30a ->\r\n GHC.Word.W64#\r\n (GHC.Prim.narrow16Word# (GHC.Prim.and# x#_a30a 0xffff##))\r\n }\r\n\r\n-- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}\r\ntest :: Bool\r\n[GblId,\r\n Caf=NoCafRefs,\r\n Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,\r\n WorkFree=True, Expandable=True,\r\n Guidance=ALWAYS_IF(arity=0,unsat_ok=True,boring_ok=True)\r\n Tmpl= GHC.Types.True}]\r\ntest = GHC.Types.True\r\n}}}\r\n\r\nFor Word8, Word16, Word32, Word64 and Int8, Int16, Int32, Int64, I would expect GHC to never produce the {{{and}}}.","type_of_failure":"OtherFailure","blocking":[]} -->Sylvain HenrySylvain Henryhttps://gitlab.haskell.org/ghc/ghc/-/issues/16400Hadrian: support shake's --lint-fsatrace feature and fix lint errors2021-05-18T15:10:52ZdavideHadrian: support shake's --lint-fsatrace feature and fix lint errorsShake's `--lint-fsatrace` feature uses [fsatrace](https://github.com/jacereda/fsatrace) to track file accesses of external commands. This allows for more accurate dependency linting which is important e.g. for caching.
Hadrian already a...Shake's `--lint-fsatrace` feature uses [fsatrace](https://github.com/jacereda/fsatrace) to track file accesses of external commands. This allows for more accurate dependency linting which is important e.g. for caching.
Hadrian already accepts the `--lint-fsatrace` command line option (it is passed on to shake automatically), but it currently has no effect. The shake options are not set correctly (In particular [shakeLintInside](https://github.com/jacereda/fsatrace) must be set).
Required Changes:
1. [shakeLintInside](https://github.com/jacereda/fsatrace) must be set
1. Out of tree build dirs don't get linted.
```
buildRoot -/- "lint-test" %> \out ->
let gen t f = cmd Shell "echo" t ">" (toNative f) :: Action ()
gen "x" $ out <.> "txt"
need [out <.> "txt"] -- This need should set off a lint error.
writeFile' out ""
```
- fsatrace gives absolute paths. Shake then tries and fails to convert to relative paths [here](https://github.com/ndmitchell/shake/blob/master/src/Development/Shake/Command.hs#L148). Stuck with an unexpected absolute path, shake thinks the file isn't needed even thought the relative path \*\*is\*\* needed.
# How To Collect Stats
To collect fsatrace lint errors as reported below, you need to modify Shake to warn instead of error on fsatrace lint errors. Have a look at [this commit of shake](https://github.com/DavidEichmann/shake/commit/60f6c7951d072c6445138fecb89569b0cb8044be) (from this [branch](https://github.com/DavidEichmann/shake/commits/WarnLint)) for how to do that. Then you'll want to do a clean build with linting enabled and save the output to a file e.g.:
```
$ ./boot && ./configure
$ (./hadrian/build.sh -j --lint-fsatrace 2>&1) > build.out
```
Then you can use [breakdown.hs](/uploads/3026bbd26c3c02d1bfd1be2b73f88d7b/breakdown.hs) to extract and compare lint error counts between builds:
```
$ runhaskell ~/breakdown.hs build_01.out build_02.out
```
You can also pass the same file twice to just get the counts of one run.
# Status
This uses a stage0 compiler with support for `-include-cpp-deps` (see [comment](https://gitlab.haskell.org/ghc/ghc/issues/16400#note_206615) below)
Remaining lint errors by file extension
| Extension | Missing Need - Error Count |
|-|-|
| .h | 84956 |
| .hs-boot | 108 |
| .so | 15 |
| .hs | 3 |
| .gz | 1 |
| .hs-incl | 1 |
| Extension | Late Need - Error Count |
|-|-|
| .h | 4012 |
| .so | 8 |
| .hs-incl | 1 |
I've tried to break these errors down into some specific cases as follows. Each point roughly corresponds to a single issue (though this is just an educated guess). Have a look at this [build output](/uploads/0b79ba9382d03cd1e101b7be076ccd4d/after_03_304643_stage0_cpp_deps.zip) and grep for "@@@" to find relevant errors.
* [ ] (~ 83.5k errors) #16868 `/include//*.h` dependencies used in later stage of ghc copiler (see [comment](https://gitlab.haskell.org/ghc/ghc/issues/16621#note_202939)).
* [ ] (~ 4k errors) `_build/generated/*.h` used/late need for many `.o` file rules.
* [ ] (108 errors) #16815 `.hs-boot` used but not depended upon in rule for `dependencies.mk`. This is from dependency generation using `ghc -M`.
* [ ] other `.hs`/`.h` files used but not depended upon in rule for `dependencies.mk`.
* [ ] (2 errors) `includes/CodeGen.Platform.hs` used but not depended upon in rule for `dependencies.mk`
* [ ] (1 errors) `libraries/filepath/System/FilePath/Internal.hs` used but not depended upon in rule for `_build/stage1/libraries/filepath/.dependencies.mk`
* [x] (~ 72 errors) #16983 in rule for `_build/generated/platformConstants`. I think this file is a bit of a special case.
* [ ] (12 errors) `libffi.so` needed after being used when linking various ways of rts .so.
* [ ] (9 errors) `libffi.so` used but not depended upon in rule for linking some binaries.
* [ ] (2 errors) `_build/stage0/compiler/build/primop-commutable.hs-incl` late need in rule for `_build/stage0/compiler/build/PrimOp.o`
* [ ] (1 error) `libffi-tarballs/libffi-3.99999+git20171002+77e130c.tar.gz` used but not depended upon in rule for `../stage1/libffi/build/Makefile.in ../stage1/libffi/build/configure`
Things already finished:
* [X] ([~ 1.8k errors](https://gitlab.haskell.org/ghc/ghc/issues/16621#note_202285)) CPP dependencies !845David EichmanndavideDavid Eichmannhttps://gitlab.haskell.org/ghc/ghc/-/issues/16399Error when running --share2020-01-05T18:31:39ZOleg GrenrusError when running --shareOn a fresh checkout, db039a4a10fc8fa9e03e6781d1c0dc33151beda6
```
# succeeds
./hadrian/build.sh --progress-colour=Never --share=_share -j3
...
# fails
./hadrian/build.sh --progress-colour=Never --share=_share -j3 --build-root=_build-e...On a fresh checkout, db039a4a10fc8fa9e03e6781d1c0dc33151beda6
```
# succeeds
./hadrian/build.sh --progress-colour=Never --share=_share -j3
...
# fails
./hadrian/build.sh --progress-colour=Never --share=_share -j3 --build-root=_build-experiment
...
# this succeeds ok
./hadrian/build.sh --progress-colour=Never --share=_share -j3
...
Build completed in 6.97s
# Trying without share: still fails with the same error
./hadrian/build.sh --progress-colour=Never -j3 --build-root=_build-experiment
...
| Run Ghc CompileHs Stage1: libraries/ghc-prim/GHC/Classes.hs => _build-baseline/stage1/libraries/ghc-prim/build/GHC/Classes.p_o
Error when running Shake build system:
at action, called at src/Rules.hs:35:19 in main:Rules
at need, called at src/Rules.hs:52:5 in main:Rules
* Depends on: _build-baseline/stage1/bin/ghc-pkg
at need, called at src/Utilities.hs:71:18 in main:Utilities
* Depends on: _build-baseline/stage1/libraries/integer-gmp/build/libHSinteger-gmp-1.0.2.0-ghc8.9.20190306.so
at need, called at src/Rules/Gmp.hs:14:5 in main:Rules.Gmp
* Depends on: _build-baseline/stage1/gmp/include/ghc-gmp.h
at need, called at src/Development/Shake/Internal/Derived.hs:118:15 in shake-0.17.6-ef5d6f7a92b6a347b5077f2591e0d47990d974d264275e5e4048829d4b393706:Development.Shake.Internal.Derived
* Depends on: _build-baseline/stage1/libraries/integer-gmp/build/config.mk
at error, called at src/Development/Shake/Internal/Rules/File.hs:180:58 in shake-0.17.6-ef5d6f7a92b6a347b5077f2591e0d47990d974d264275e5e4048829d4b393706:Development.Shake.Internal.Rules.File
* Raised the exception:
Error, file does not exist and no rule available:
_build-baseline/stage1/libraries/integer-gmp/build/config.mk
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------------- |
| Version | |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Build System (Hadrian) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Error when running --share","status":"New","operating_system":"","component":"Build System (Hadrian)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"On a fresh checkout, db039a4a10fc8fa9e03e6781d1c0dc33151beda6\r\n\r\n{{{\r\n# succeeds\r\n./hadrian/build.sh --progress-colour=Never --share=_share -j3\r\n...\r\n\r\n# fails\r\n./hadrian/build.sh --progress-colour=Never --share=_share -j3 --build-root=_build-experiment\r\n...\r\n\r\n# this succeeds ok\r\n./hadrian/build.sh --progress-colour=Never --share=_share -j3\r\n...\r\nBuild completed in 6.97s\r\n\r\n# Trying without share: still fails with the same error\r\n./hadrian/build.sh --progress-colour=Never -j3 --build-root=_build-experiment\r\n...\r\n| Run Ghc CompileHs Stage1: libraries/ghc-prim/GHC/Classes.hs => _build-baseline/stage1/libraries/ghc-prim/build/GHC/Classes.p_o\r\nError when running Shake build system:\r\n at action, called at src/Rules.hs:35:19 in main:Rules\r\n at need, called at src/Rules.hs:52:5 in main:Rules\r\n* Depends on: _build-baseline/stage1/bin/ghc-pkg\r\n at need, called at src/Utilities.hs:71:18 in main:Utilities\r\n* Depends on: _build-baseline/stage1/libraries/integer-gmp/build/libHSinteger-gmp-1.0.2.0-ghc8.9.20190306.so\r\n at need, called at src/Rules/Gmp.hs:14:5 in main:Rules.Gmp\r\n* Depends on: _build-baseline/stage1/gmp/include/ghc-gmp.h\r\n at need, called at src/Development/Shake/Internal/Derived.hs:118:15 in shake-0.17.6-ef5d6f7a92b6a347b5077f2591e0d47990d974d264275e5e4048829d4b393706:Development.Shake.Internal.Derived\r\n* Depends on: _build-baseline/stage1/libraries/integer-gmp/build/config.mk\r\n at error, called at src/Development/Shake/Internal/Rules/File.hs:180:58 in shake-0.17.6-ef5d6f7a92b6a347b5077f2591e0d47990d974d264275e5e4048829d4b393706:Development.Shake.Internal.Rules.File\r\n* Raised the exception:\r\nError, file does not exist and no rule available:\r\n _build-baseline/stage1/libraries/integer-gmp/build/config.mk\r\n\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16396TH doesn't preserve `forall`2020-05-11T23:26:18ZRichard Eisenbergrae@richarde.devTH doesn't preserve `forall`I think there are several bugs in the way TH currently deals with type variable quantification.
- \*Background\*\*
GHC uses the "forall-or-nothing" rule. This means that, if there is a top-level `forall` in a type signature, that `fora...I think there are several bugs in the way TH currently deals with type variable quantification.
- \*Background\*\*
GHC uses the "forall-or-nothing" rule. This means that, if there is a top-level `forall` in a type signature, that `forall` must bind *all* variables being brought into scope in that signature. Examples:
```hs
f1 :: a -> a
f1 x = x -- OK, no forall
f2 :: forall . a -> a
f2 x = x -- rejected
f3 :: forall a. a -> a
f3 x = x -- OK, forall binds all variables
f4 :: forall a. a -> a
f4 x = helper x
where helper :: a -> a -- OK; this uses a already in scope
helper _ = x
f5 :: forall a. a -> a
f5 x = helper x
where helper :: forall . a -> a -- OK; a is already in scope
helper _ = x
f6 :: forall a. a -> a
f6 x = helper x
where helper :: forall a. a -> a -- this is a new variable `a`
helper _ = x -- rejected; the two `a`s are different
```
Upshot: the existence of `forall` matters.
- \*Strangeness 1\*\*
```hs
foo1 :: $([t| a -> a |])
foo1 x = x
```
is rejected, because `a` is not in scope. This is incongruent with the treatment of `f1`. One could argue, though, that all type variables used in quotes should be in scope. I would disagree with such an argument (that's not what we do these days in terms), but it's not silly.
- \*Strangeness 2\*\*
```hs
foo2 :: $([t| $(varT (mkName "a")) -> $(varT (mkName "a")) |])
foo2 x = x
```
is rejected because `a` is not in scope. This behavior seems just wrong.
- \*Strangeness 3\*\*
```hs
foo3 :: $([t| forall . $(varT (mkName "a")) -> $(varT (mkName "a")) |])
foo3 x = x
```
is rejected in the same way as `foo2`. While this *should* be rejected (it's `f2`), `-ddump-splices` says that the splice evaluates to `a -> a`; note: no `forall`. So it's rejected under false pretenses.
- \*Strangeness 4\*\*
```hs
foo4 :: $([t| forall a . $(varT (mkName "a")) -> $(varT (mkName "a")) |])
foo4 x = x
```
This one is accepted (as it should be), but it produces a warning!
```
Scratch.hs:51:21: warning: [-Wunused-foralls]
Unused quantified type variable ‘a’
In the type ‘forall a.
$(varT (mkName "a")) -> $(varT (mkName "a"))’
|
51 | foo :: $([t| forall a . $(varT (mkName "a")) -> $(varT (mkName "a")) |])
|
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 8.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Template Haskell |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"TH doesn't preserve `forall`","status":"New","operating_system":"","component":"Template Haskell","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I think there are several bugs in the way TH currently deals with type variable quantification.\r\n\r\n**Background**\r\n\r\nGHC uses the \"forall-or-nothing\" rule. This means that, if there is a top-level `forall` in a type signature, that `forall` must bind ''all'' variables being brought into scope in that signature. Examples:\r\n\r\n{{{#!hs\r\nf1 :: a -> a\r\nf1 x = x -- OK, no forall\r\n\r\nf2 :: forall . a -> a\r\nf2 x = x -- rejected\r\n\r\nf3 :: forall a. a -> a\r\nf3 x = x -- OK, forall binds all variables\r\n\r\nf4 :: forall a. a -> a\r\nf4 x = helper x\r\n where helper :: a -> a -- OK; this uses a already in scope\r\n helper _ = x\r\n\r\nf5 :: forall a. a -> a\r\nf5 x = helper x\r\n where helper :: forall . a -> a -- OK; a is already in scope\r\n helper _ = x\r\n\r\nf6 :: forall a. a -> a\r\nf6 x = helper x\r\n where helper :: forall a. a -> a -- this is a new variable `a`\r\n helper _ = x -- rejected; the two `a`s are different\r\n}}}\r\n\r\nUpshot: the existence of `forall` matters.\r\n\r\n**Strangeness 1**\r\n\r\n{{{#!hs\r\nfoo1 :: $([t| a -> a |])\r\nfoo1 x = x\r\n}}}\r\n\r\nis rejected, because `a` is not in scope. This is incongruent with the treatment of `f1`. One could argue, though, that all type variables used in quotes should be in scope. I would disagree with such an argument (that's not what we do these days in terms), but it's not silly.\r\n\r\n**Strangeness 2**\r\n\r\n{{{#!hs\r\nfoo2 :: $([t| $(varT (mkName \"a\")) -> $(varT (mkName \"a\")) |])\r\nfoo2 x = x\r\n}}}\r\n\r\nis rejected because `a` is not in scope. This behavior seems just wrong.\r\n\r\n**Strangeness 3**\r\n\r\n{{{#!hs\r\nfoo3 :: $([t| forall . $(varT (mkName \"a\")) -> $(varT (mkName \"a\")) |])\r\nfoo3 x = x\r\n}}}\r\n\r\nis rejected in the same way as `foo2`. While this ''should'' be rejected (it's `f2`), `-ddump-splices` says that the splice evaluates to `a -> a`; note: no `forall`. So it's rejected under false pretenses.\r\n\r\n**Strangeness 4**\r\n\r\n{{{#!hs\r\nfoo4 :: $([t| forall a . $(varT (mkName \"a\")) -> $(varT (mkName \"a\")) |])\r\nfoo4 x = x\r\n}}}\r\n\r\nThis one is accepted (as it should be), but it produces a warning!\r\n\r\n{{{\r\nScratch.hs:51:21: warning: [-Wunused-foralls]\r\n Unused quantified type variable ‘a’\r\n In the type ‘forall a.\r\n $(varT (mkName \"a\")) -> $(varT (mkName \"a\"))’\r\n |\r\n51 | foo :: $([t| forall a . $(varT (mkName \"a\")) -> $(varT (mkName \"a\")) |])\r\n | \r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16390T10672 fails2020-01-21T14:15:37ZBen GamariT10672 failsThis test, which is only run on Windows, seems to be reliably timing out.
Marking as broken.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version ...This test, which is only run on Windows, seems to be reliably timing out.
Marking as broken.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"T10672 fails","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.10.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"This test, which is only run on Windows, seems to be reliably timing out.\r\n\r\nMarking as broken.","type_of_failure":"OtherFailure","blocking":[]} -->8.10.2https://gitlab.haskell.org/ghc/ghc/-/issues/16388T15904 fails on Windows2020-01-21T14:15:37ZBen GamariT15904 fails on Windows```
=====> T15904(normal) 2036 of 6839 [0, 6, 0]
cd "hp2ps/T15904.run" && $MAKE -s --no-print-directory T15904
Wrong exit code for T15904()(expected 0 , actual 2 )
Stdout ( T15904 ):
[1 of 1] Compiling T15904 ( T15904.hs, T15...```
=====> T15904(normal) 2036 of 6839 [0, 6, 0]
cd "hp2ps/T15904.run" && $MAKE -s --no-print-directory T15904
Wrong exit code for T15904()(expected 0 , actual 2 )
Stdout ( T15904 ):
[1 of 1] Compiling T15904 ( T15904.hs, T15904.o )
Linking "T15904".exe ...
Stderr ( T15904 ):
"T15904".exe.manifest: openFile: invalid argument (Invalid argument)
make[2]: *** [Makefile:7: T15904] Error 1
*** unexpected failure for T15904(normal)
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | Phyx- |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"T15904 fails on Windows","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.10.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["Phyx-"],"type":"Bug","description":"{{{\r\n=====> T15904(normal) 2036 of 6839 [0, 6, 0]\r\ncd \"hp2ps/T15904.run\" && $MAKE -s --no-print-directory T15904 \r\nWrong exit code for T15904()(expected 0 , actual 2 )\r\nStdout ( T15904 ):\r\n[1 of 1] Compiling T15904 ( T15904.hs, T15904.o )\r\nLinking \"T15904\".exe ...\r\nStderr ( T15904 ):\r\n\"T15904\".exe.manifest: openFile: invalid argument (Invalid argument)\r\nmake[2]: *** [Makefile:7: T15904] Error 1\r\n*** unexpected failure for T15904(normal)\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.10.2https://gitlab.haskell.org/ghc/ghc/-/issues/16386T16219 fails on Windows2020-01-21T14:15:36ZBen GamariT16219 fails on Windows```
=====> T16219(normal) 85 of 6839 [0, 0, 0]
cd "backpack/cabal/T16219/T16219.run" && $MAKE -s --no-print-directory T16219 CLEANUP=1
Wrong exit code for T16219()(expected 0 , actual 2 )
Stderr ( T16219 ):
C:\GitLabRunner\builds\8fc0e...```
=====> T16219(normal) 85 of 6839 [0, 0, 0]
cd "backpack/cabal/T16219/T16219.run" && $MAKE -s --no-print-directory T16219 CLEANUP=1
Wrong exit code for T16219()(expected 0 , actual 2 )
Stderr ( T16219 ):
C:\GitLabRunner\builds\8fc0e283\0\ghc\ghc\inplace\lib\../mingw/bin\ar.exe: dist\build\backpack-issue-0.1.0.0-60IHJZyC3G628wj7263Sr0-library-a+Dil0EMVFuE1Kv7vqZWLGcN\objs-3388\libHSbackpack-issue-0.1.0.0-60IHJZyC3G628wj7263Sr0-library-a+Dil0EMVFuE1Kv7vqZWLGcN.a: No such file or directory
make[2]: *** [Makefile:12: T16219] Error 1
*** unexpected failure for T16219(normal)
=====> bkpcabal03(normal) 88 of 6839 [0, 1, 0]
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.4.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"T16219 fails on Windows","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"8.10.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.4.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"{{{\r\n=====> T16219(normal) 85 of 6839 [0, 0, 0]\r\ncd \"backpack/cabal/T16219/T16219.run\" && $MAKE -s --no-print-directory T16219 CLEANUP=1 \r\nWrong exit code for T16219()(expected 0 , actual 2 )\r\nStderr ( T16219 ):\r\nC:\\GitLabRunner\\builds\\8fc0e283\\0\\ghc\\ghc\\inplace\\lib\\../mingw/bin\\ar.exe: dist\\build\\backpack-issue-0.1.0.0-60IHJZyC3G628wj7263Sr0-library-a+Dil0EMVFuE1Kv7vqZWLGcN\\objs-3388\\libHSbackpack-issue-0.1.0.0-60IHJZyC3G628wj7263Sr0-library-a+Dil0EMVFuE1Kv7vqZWLGcN.a: No such file or directory\r\nmake[2]: *** [Makefile:12: T16219] Error 1\r\n*** unexpected failure for T16219(normal)\r\n=====> bkpcabal03(normal) 88 of 6839 [0, 1, 0]\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->8.10.2https://gitlab.haskell.org/ghc/ghc/-/issues/16383ghc: internal error: getMBlock: mmap: Invalid argument (gi-gtk on armv7)2019-07-07T18:00:18ZJens Petersenghc: internal error: getMBlock: mmap: Invalid argument (gi-gtk on armv7)When trying to build gi-gtk-3.0.26 with ghc-8.4.4 on Fedora 30 armv7hl, ghc crashes like this:
```
[484 of 498] Compiling GI.Gtk.Functions ( GI/Gtk/Functions.hs, dist/build/GI/Gtk/Functions.o )
BUILDSTDERR: ghc: internal error: getMBloc...When trying to build gi-gtk-3.0.26 with ghc-8.4.4 on Fedora 30 armv7hl, ghc crashes like this:
```
[484 of 498] Compiling GI.Gtk.Functions ( GI/Gtk/Functions.hs, dist/build/GI/Gtk/Functions.o )
BUILDSTDERR: ghc: internal error: getMBlock: mmap: Invalid argument
BUILDSTDERR: (GHC version 8.4.4 for arm_unknown_linux)
BUILDSTDERR: Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
BUILDSTDERR: /var/tmp/rpm-tmp.McmHQu: line 52: 5271 Aborted (core dumped) ./Setup build
```
https://koji.fedoraproject.org/koji/taskinfo?taskID=33138502
gi-gtk built fine before on ghc-8.2.2 armv7.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.4.4 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"ghc: internal error: getMBlock: mmap: Invalid argument (gi-gtk on armv7)","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.4.4","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"When trying to build gi-gtk-3.0.26 with ghc-8.4.4 on Fedora 30 armv7hl, ghc crashes like this:\r\n\r\n{{{\r\n[484 of 498] Compiling GI.Gtk.Functions ( GI/Gtk/Functions.hs, dist/build/GI/Gtk/Functions.o )\r\nBUILDSTDERR: ghc: internal error: getMBlock: mmap: Invalid argument\r\nBUILDSTDERR: (GHC version 8.4.4 for arm_unknown_linux)\r\nBUILDSTDERR: Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug\r\nBUILDSTDERR: /var/tmp/rpm-tmp.McmHQu: line 52: 5271 Aborted (core dumped) ./Setup build\r\n}}}\r\n\r\nhttps://koji.fedoraproject.org/koji/taskinfo?taskID=33138502\r\n\r\ngi-gtk built fine before on ghc-8.2.2 armv7.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16382Lifting a function from where clause to top level causes compilation time to ...2023-05-07T20:29:47ZdanidiazLifting a function from where clause to top level causes compilation time to tripleI have this program that depends on the library "red-black-record" version 2.0.2.2 on Hackage:
```hs
{-# LANGUAGE DataKinds, TypeApplications #-}
module Main where
import Data.RBR (FromList,Delete,Variant,I,injectI,winnowI,match)
impo...I have this program that depends on the library "red-black-record" version 2.0.2.2 on Hackage:
```hs
{-# LANGUAGE DataKinds, TypeApplications #-}
module Main where
import Data.RBR (FromList,Delete,Variant,I,injectI,winnowI,match)
import GHC.TypeLits
type Phase01 = FromList '[
'("ctor1",Int), '("ctor2",Bool), '("ctor4",Char), '("ctor3",Char),
'("ctor6",Char), '("ctor5",Char), '("ctor10",Char), '("ctor11",Char),
'("ctor13",Char), '("ctor14",Char), '("ctor39",Char), '("ctor46",Char),
'("ctor47",Char), '("ctor44",Char), '("ctor43",Char), '("ctor7",Char),
'("ctor9",Char), '("ctor20",Char), '("ctor45",Char), '("ctor21",Char),
'("ctor48",Char), '("ctor49",Char), '("ctor50",Char), '("ctor41",Char),
'("ctor33",Char), '("ctor32",Char), '("ctor42",Char), '("ctor22",Char),
'("ctor23",Char), '("ctor8",Char), '("ctor40",Char), '("ctor29",Char),
'("ctor24",Char), '("ctor38",Char), '("ctor25",Char), '("ctor26",Char),
'("ctor27",Char), '("ctor28",Char), '("ctor36",Char), '("ctor52",Char),
'("ctor51",Char), '("ctor53",Char), '("ctor12",Char), '("ctor54",Char),
'("ctor15",Char), '("ctor31",Char), '("ctor30",Char), '("ctor34",Char),
'("ctor35",Char), '("ctor17",Char), '("ctor16",Char), '("ctor18",Char),
'("ctor19",Char), '("ctor37",Char)
]
type Phase02 = Delete "ctor1" Int Phase01
main :: IO ()
main = print (match @"ctor17" (fromPhase1ToPhase2 (injectI @"ctor1" 2)))
where
fromPhase1ToPhase2 :: Variant I Phase01 -> Variant I Phase02
fromPhase1ToPhase2 v = case winnowI @"ctor1" @Int v of
Right z -> injectI @"ctor2" False
Left l -> l
```
"red-black-record" provides extensible variants; the code is basically removing a branch from a variant with 50-plus branches, and then trying to match another branch. It is type family-heavy code.
The code as it is takes \*\*\~9 seconds\*\* to compile on my machine. But when I move the `fromPhase1ToPhase2` function to the top level (including the signature) compilation time balloons to \*\*\~ 29 seconds\*\*. Is there a reason it should be so?
As another datapoint, moving the function to the top level but omitting the complex type-level map parameters (`Phase01`, `Phase02`) using partial type signatures (also requires a new type application) compiles in \*\*\~9 seconds\*\* again.
```hs
{-# LANGUAGE PartialTypeSignatures #-}
{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
-- ...
type Phase02 = Delete "ctor1" Int Phase01
fromPhase1ToPhase2 :: Variant I _ -> Variant I _
fromPhase1ToPhase2 v = case winnowI @"ctor1" @Int @Phase01 v of
Right z -> injectI @"ctor2" False
Left l -> l
main :: IO ()
main = print (match @"ctor17" (fromPhase1ToPhase2 (injectI @"ctor1" 2)))
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.4.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Lifting a function from where clause to top level causes compilation time to triple","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.4.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I have this program that depends on the library \"red-black-record\" version 2.0.2.2 on Hackage:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE DataKinds, TypeApplications #-}\r\nmodule Main where\r\n\r\nimport Data.RBR (FromList,Delete,Variant,I,injectI,winnowI,match)\r\n\r\nimport GHC.TypeLits\r\n\r\ntype Phase01 = FromList '[ \r\n '(\"ctor1\",Int), '(\"ctor2\",Bool), '(\"ctor4\",Char), '(\"ctor3\",Char),\r\n '(\"ctor6\",Char), '(\"ctor5\",Char), '(\"ctor10\",Char), '(\"ctor11\",Char),\r\n '(\"ctor13\",Char), '(\"ctor14\",Char), '(\"ctor39\",Char), '(\"ctor46\",Char),\r\n '(\"ctor47\",Char), '(\"ctor44\",Char), '(\"ctor43\",Char), '(\"ctor7\",Char),\r\n '(\"ctor9\",Char), '(\"ctor20\",Char), '(\"ctor45\",Char), '(\"ctor21\",Char),\r\n '(\"ctor48\",Char), '(\"ctor49\",Char), '(\"ctor50\",Char), '(\"ctor41\",Char),\r\n '(\"ctor33\",Char), '(\"ctor32\",Char), '(\"ctor42\",Char), '(\"ctor22\",Char),\r\n '(\"ctor23\",Char), '(\"ctor8\",Char), '(\"ctor40\",Char), '(\"ctor29\",Char),\r\n '(\"ctor24\",Char), '(\"ctor38\",Char), '(\"ctor25\",Char), '(\"ctor26\",Char),\r\n '(\"ctor27\",Char), '(\"ctor28\",Char), '(\"ctor36\",Char), '(\"ctor52\",Char),\r\n '(\"ctor51\",Char), '(\"ctor53\",Char), '(\"ctor12\",Char), '(\"ctor54\",Char),\r\n '(\"ctor15\",Char), '(\"ctor31\",Char), '(\"ctor30\",Char), '(\"ctor34\",Char),\r\n '(\"ctor35\",Char), '(\"ctor17\",Char), '(\"ctor16\",Char), '(\"ctor18\",Char),\r\n '(\"ctor19\",Char), '(\"ctor37\",Char)\r\n ]\r\n\r\ntype Phase02 = Delete \"ctor1\" Int Phase01\r\n\r\nmain :: IO ()\r\nmain = print (match @\"ctor17\" (fromPhase1ToPhase2 (injectI @\"ctor1\" 2)))\r\n where\r\n fromPhase1ToPhase2 :: Variant I Phase01 -> Variant I Phase02\r\n fromPhase1ToPhase2 v = case winnowI @\"ctor1\" @Int v of \r\n Right z -> injectI @\"ctor2\" False\r\n Left l -> l\r\n}}}\r\n\r\n\"red-black-record\" provides extensible variants; the code is basically removing a branch from a variant with 50-plus branches, and then trying to match another branch. It is type family-heavy code.\r\n\r\nThe code as it is takes **~9 seconds** to compile on my machine. But when I move the `fromPhase1ToPhase2` function to the top level (including the signature) compilation time balloons to **~29 seconds**. Is there a reason it should be so?\r\n\r\nAs another datapoint, moving the function to the top level but omitting the complex type-level map parameters (`Phase01`, `Phase02`) using partial type signatures (also requires a new type application) compiles in **~9 seconds** again.\r\n\r\n{{{#!hs\r\n{-# LANGUAGE PartialTypeSignatures #-}\r\n{-# OPTIONS_GHC -Wno-partial-type-signatures #-}\r\n\r\n-- ...\r\n\r\ntype Phase02 = Delete \"ctor1\" Int Phase01\r\n\r\nfromPhase1ToPhase2 :: Variant I _ -> Variant I _\r\nfromPhase1ToPhase2 v = case winnowI @\"ctor1\" @Int @Phase01 v of \r\n Right z -> injectI @\"ctor2\" False\r\n Left l -> l\r\n\r\nmain :: IO ()\r\nmain = print (match @\"ctor17\" (fromPhase1ToPhase2 (injectI @\"ctor1\" 2)))\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16380HPC's CLI is awkward2019-07-07T18:00:19ZMaxGabrielHPC's CLI is awkwardhpc's command line interface could be brought more in line with other Haskell tools (and most CLIs I've used). I would expect all of the following commands to work:
```
hpc --version
hpc --help
hpc markup --help
```
Currently these com...hpc's command line interface could be brought more in line with other Haskell tools (and most CLIs I've used). I would expect all of the following commands to work:
```
hpc --version
hpc --help
hpc markup --help
```
Currently these commands are:
```
hpc version
hpc help
hpc help markup
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Code Coverage |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"HPC's CLI is awkward","status":"New","operating_system":"","component":"Code Coverage","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"hpc's command line interface could be brought more in line with other Haskell tools (and most CLIs I've used). I would expect all of the following commands to work:\r\n\r\n{{{\r\nhpc --version\r\nhpc --help\r\nhpc markup --help\r\n}}}\r\n\r\nCurrently these commands are:\r\n\r\n{{{\r\nhpc version\r\nhpc help\r\nhpc help markup\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16374Cannot deduce constraint from itself with poly-kinded type family2019-07-07T18:00:20ZrolandCannot deduce constraint from itself with poly-kinded type familyCompiling
```hs
{-# LANGUAGE PolyKinds, TypeFamilies #-}
module Eq where
type family F a :: k where
withEq :: F Int ~ F Bool => a
withEq = undefined
```
gives an arguably confusing error message:
```
Eq.hs:7:11: error:
• Could ...Compiling
```hs
{-# LANGUAGE PolyKinds, TypeFamilies #-}
module Eq where
type family F a :: k where
withEq :: F Int ~ F Bool => a
withEq = undefined
```
gives an arguably confusing error message:
```
Eq.hs:7:11: error:
• Could not deduce: F Int ~ F Bool
from the context: F Int ~ F Bool
bound by the type signature for:
withEq :: forall k a. (F Int ~ F Bool) => a
at Eq.hs:7:11-29
NB: ‘F’ is a non-injective type family
The type variable ‘k0’ is ambiguous
• In the ambiguity check for ‘withEq’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature: withEq :: F Int ~ F Bool => a
```
I'm not claiming this program should necessarily typecheck, but "Cannot deduce X from the context X" induces head-scratching.
Replacing `k` with `*` in the definition of `F` makes the error go away.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------------- |
| Version | 8.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (Type checker) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Cannot deduce constraint from itself with poly-kinded type family","status":"New","operating_system":"","component":"Compiler (Type checker)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Compiling\r\n{{{#!hs\r\n{-# LANGUAGE PolyKinds, TypeFamilies #-}\r\n\r\nmodule Eq where\r\n\r\ntype family F a :: k where\r\n\r\nwithEq :: F Int ~ F Bool => a\r\nwithEq = undefined\r\n}}}\r\n\r\ngives an arguably confusing error message:\r\n\r\n{{{\r\nEq.hs:7:11: error:\r\n • Could not deduce: F Int ~ F Bool\r\n from the context: F Int ~ F Bool\r\n bound by the type signature for:\r\n withEq :: forall k a. (F Int ~ F Bool) => a\r\n at Eq.hs:7:11-29\r\n NB: ‘F’ is a non-injective type family\r\n The type variable ‘k0’ is ambiguous\r\n • In the ambiguity check for ‘withEq’\r\n To defer the ambiguity check to use sites, enable AllowAmbiguousTypes\r\n In the type signature: withEq :: F Int ~ F Bool => a\r\n}}}\r\n\r\nI'm not claiming this program should necessarily typecheck, but \"Cannot deduce X from the context X\" induces head-scratching.\r\n\r\nReplacing `k` with `*` in the definition of `F` makes the error go away.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16372GHC can't constant fold even basic power (^) applications for Int (and others?)2019-07-07T18:00:20ZMateusz KowalczykGHC can't constant fold even basic power (^) applications for Int (and others?)```hs
[nix-shell:/tmp]$ ghc -O2 -fforce-recomp -ddump-simpl S.hs 2>&1 | tail
[GblId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 50 20}]
foo
= case GHC...```hs
[nix-shell:/tmp]$ ghc -O2 -fforce-recomp -ddump-simpl S.hs 2>&1 | tail
[GblId,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False,
WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 50 20}]
foo
= case GHC.Real.$wf1 2# 1# of ww2_a2zt { __DEFAULT ->
GHC.Types.I# ww2_a2zt
}
[nix-shell:/tmp]$ cat S.hs
module S (foo) where
foo :: Int
foo = (2 :: Int) ^ (1 :: Int)
```
This seems like a fairly strange thing to not optimise when constants are known on both sides. I'm complaining about Int for this particular ticket.https://gitlab.haskell.org/ghc/ghc/-/issues/16371GHC should be more forgiving with visible dependent quantification in visible...2020-11-09T15:26:20ZRyan ScottGHC should be more forgiving with visible dependent quantification in visible type applicationsGHC HEAD currently rejects the following code:
```hs
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Bug where
imp...GHC HEAD currently rejects the following code:
```hs
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Bug where
import Data.Kind
import Data.Proxy
f :: forall k (a :: k). Proxy a
f = Proxy
g :: forall (a :: forall x -> x -> Type). Proxy a
g = f @(forall x -> x -> Type) @a
```
```
GHCi, version 8.9.20190227: https://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
[1 of 1] Compiling Bug ( Bug.hs, interpreted )
Bug.hs:14:6: error:
• Illegal visible, dependent quantification in the type of a term:
forall x -> x -> *
(GHC does not yet support this)
• In the type signature:
g :: forall (a :: forall x -> x -> Type). Proxy a
|
14 | g :: forall (a :: forall x -> x -> Type). Proxy a
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
```
This test is implemented in `TcValidity.vdqAllowed`.
But GHC is being too conservative here. `forall x -> x -> *` _isn't_ the type of a term here, but rather the kind of a type variable, and it's perfectly admissible to use visible dependent quantification in such a scenario.
The immediate reason that this happens is because of this code:
```hs
vdqAllowed (TypeAppCtxt {}) = False
```
Unfortunately, fixing this bug isn't as simply as changing `False` to `True`. If you do that, then GHC becomes _too_ forgiving and allows things like this:
```hs
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
lol :: forall a. a
lol = undefined
t2 = lol @(forall a -> a -> a)
```
Here, visible dependent quantification is leaking into the type of a term, which we definitely don't want to happen.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------------- |
| Version | 8.9 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (Type checker) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHC should be more forgiving with visible dependent quantification in visible type applications","status":"New","operating_system":"","component":"Compiler (Type checker)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.9","keywords":["VisibleDependentQuantification"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"GHC HEAD currently rejects the following code:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE ImpredicativeTypes #-}\r\n{-# LANGUAGE PolyKinds #-}\r\n{-# LANGUAGE RankNTypes #-}\r\n{-# LANGUAGE ScopedTypeVariables #-}\r\n{-# LANGUAGE TypeApplications #-}\r\nmodule Bug where\r\n\r\nimport Data.Kind\r\nimport Data.Proxy\r\n\r\nf :: forall k a. Proxy a\r\nf = Proxy\r\n\r\ng :: forall (a :: forall x -> x -> Type). Proxy a\r\ng = f @(forall x -> x -> Type) @a\r\n}}}\r\n{{{\r\nGHCi, version 8.9.20190227: https://www.haskell.org/ghc/ :? for help\r\nLoaded GHCi configuration from /home/rgscott/.ghci\r\n[1 of 1] Compiling Bug ( Bug.hs, interpreted )\r\n\r\nBug.hs:14:6: error:\r\n • Illegal visible, dependent quantification in the type of a term:\r\n forall x -> x -> *\r\n (GHC does not yet support this)\r\n • In the type signature:\r\n g :: forall (a :: forall x -> x -> Type). Proxy a\r\n |\r\n14 | g :: forall (a :: forall x -> x -> Type). Proxy a\r\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n}}}\r\n\r\nBut GHC is being too conservative here. `forall x -> x -> *` //isn't// the type of a term here, but rather the kind of a type variable, and it's perfectly admissible to use visible dependent quantification in such a scenario.\r\n\r\nThe immediate reason that this happens is because of this code:\r\n\r\n{{{#!hs\r\nvdqAllowed (TypeAppCtxt {}) = False\r\n}}}\r\n\r\nUnfortunately, fixing this bug isn't as simply as changing `False` to `True`. If you do that, then GHC becomes //too// forgiving and allows things like this:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE ImpredicativeTypes #-}\r\n{-# LANGUAGE PolyKinds #-}\r\n{-# LANGUAGE RankNTypes #-}\r\n{-# LANGUAGE TypeApplications #-}\r\n\r\nlol :: forall a. a\r\nlol = undefined\r\n\r\nt2 = lol @(forall a -> a -> a)\r\n}}}\r\n\r\nHere, visible dependent quantification is leaking into the type of a term, which we definitely don't want to happen.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16369Implement testing of stage1 in ./validate --hadrian2021-08-16T07:50:54ZAlp MestanogullariImplement testing of stage1 in ./validate --hadrianWhile `master` doesn't support `./validate --hadrian` yet, most of that patch is ready in [!326](https://gitlab.haskell.org/ghc/ghc/merge_requests/326) and will be split up in a few MRs to make review & landing easier. However, it doesn'...While `master` doesn't support `./validate --hadrian` yet, most of that patch is ready in [!326](https://gitlab.haskell.org/ghc/ghc/merge_requests/326) and will be split up in a few MRs to make review & landing easier. However, it doesn't yet implement testing of the stage 1 compiler, just stage 2. This ticket serves as a reminder to implement testing of stage 1 with hadrian in the validate script.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------------- |
| Version | 8.7 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | Build System (Hadrian) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Implement testing of stage1 in ./validate --hadrian","status":"New","operating_system":"","component":"Build System (Hadrian)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"While `master` doesn't support `./validate --hadrian` yet, most of that patch is ready in [https://gitlab.haskell.org/ghc/ghc/merge_requests/326 !326] and will be split up in a few MRs to make review & landing easier. However, it doesn't yet implement testing of the stage 1 compiler, just stage 2. This ticket serves as a reminder to implement testing of stage 1 with hadrian in the validate script.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16366Strict version of `foldlM`.2020-06-26T05:29:08ZautotakerStrict version of `foldlM`.`Data.Foldable.foldlM` is lazy on the accumulation parameter.
A user can define
`foldlM (\acc x -> acc `seq` step acc x) z xs`,
but actually this function is NOT strict! It is simplified to the following core:
```hs
foldlM (\acc x -> a...`Data.Foldable.foldlM` is lazy on the accumulation parameter.
A user can define
`foldlM (\acc x -> acc `seq` step acc x) z xs`,
but actually this function is NOT strict! It is simplified to the following core:
```hs
foldlM (\acc x -> acc `seq` step acc x) z xs
==
go xs z where
go [] acc = pure acc
go (x:xs) acc = (acc `seq` step acc x) >>= go xs
```
DemandAnalysis infers that `go` is lazy on the second argument
because `pure` is lazy in general (e.g. `IO` Monad).
Thus `foldlM'` is needed.
Its definition would be:
```hs
foldlM' :: (Monad m, Foldable t) => (b -> a -> m b) -> b -> t a -> m b
foldlM' f z0 xs = foldr c (\x -> x `seq` pure x) xs z0
where c x k = \z -> z `seq` (f z x >>= k)
{-# INLINE c #-}
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 8.6.3 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Strict version of `foldlM`.","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"`Data.Foldable.foldlM` is lazy on the accumulation parameter.\r\n\r\nA user can define \r\n{{{foldlM (\\acc x -> acc `seq` step acc x) z xs}}},\r\nbut actually this function is NOT strict! It is simplified to the following core:\r\n{{{#!hs\r\nfoldlM (\\acc x -> acc `seq` step acc x) z xs\r\n ==\r\ngo xs z where\r\n go [] acc = pure acc\r\n go (x:xs) acc = (acc `seq` step acc x) >>= go xs\r\n}}}\r\nDemandAnalysis infers that `go` is lazy on the second argument\r\nbecause `pure` is lazy in general (e.g. `IO` Monad).\r\n\r\nThus `foldlM'` is needed.\r\n\r\nIts definition would be:\r\n{{{#!hs\r\nfoldlM' :: (Monad m, Foldable t) => (b -> a -> m b) -> b -> t a -> m b\r\nfoldlM' f z0 xs = foldr c (\\x -> x `seq` pure x) xs z0\r\n where c x k = \\z -> z `seq` (f z x >>= k)\r\n {-# INLINE c #-}\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16365Inconsistency in quantified constraint solving2023-07-11T21:14:02ZRyan ScottInconsistency in quantified constraint solvingConsider the following program:
```hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Q...Consider the following program:
```hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Bug where
import Data.Kind
import Data.Proxy
class C a where
m :: a -> ()
data Dict c = c => Dict
-----
type family F a :: Type -> Type
class C (F a b) => CF a b
instance C (F a b) => CF a b
works1 :: (forall z. CF a z) => Proxy (a, b) -> Dict (CF a b)
works1 _ = Dict
works2 :: ( CF a b) => Proxy (a, b) -> Dict (C (F a b))
works2 _ = Dict
works3, fails :: (forall z. CF a z) => Proxy (a, b) -> Dict (C (F a b))
works3 p | Dict <- works1 p = Dict
fails _ = Dict
```
`fails`, as its name suggests, fails to typecheck:
```
$ /opt/ghc/8.6.3/bin/ghc Bug.hs
[1 of 1] Compiling Bug ( Bug.hs, Bug.o )
Bug.hs:33:11: error:
• Could not deduce (C (F a b)) arising from a use of ‘Dict’
from the context: forall z. CF a z
bound by the type signature for:
fails :: forall a b.
(forall z. CF a z) =>
Proxy (a, b) -> Dict (C (F a b))
at Bug.hs:31:1-71
• In the expression: Dict
In an equation for ‘fails’: fails _ = Dict
|
33 | fails _ = Dict
| ^^^^
```
But I see no reason why this shouldn't typecheck. After all, the fact that `works1` typechecks proves that GHC's constraint solver is perfectly capable of deducing that `(forall z. CF a z)` implies `(CF a b)`, and the fact that `works2` typechecks proves that GHC's constraint solver is perfectly capable of deducing that `(CF a b)` implies that `(C (F a b))`. Why then can GHC's constraint solver not connect the dots and deduce that `(forall z. CF a z)` implies `(C (F a b))` (in the type of `fails`)?
Note that something with the type `(forall z. CF a z) => Proxy (a, b) -> Dict (C (F a b))` //can// be made to work if you explicitly guide GHC along with explicit pattern-matching on a `Dict`, as `works3` demonstrates. But I claim that this shouldn't be necessary.
Moreover, in this variation of the program above:
```hs
-- <as above>
-----
data G a :: Type -> Type
class C (G a b) => CG a b
instance C (G a b) => CG a b
works1' :: (forall z. CG a z) => Proxy (a, b) -> Dict (CG a b)
works1' _ = Dict
works2' :: ( CG a b) => Proxy (a, b) -> Dict (C (G a b))
works2' _ = Dict
works3' :: (forall z. CG a z) => Proxy (a, b) -> Dict (C (G a b))
works3' _ = Dict
```
`works3'` needs no explicit `Dict` pattern-matching to typecheck.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Inconsistency in quantified constraint solving","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":["QuantifiedConstraints"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Consider the following program:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE ConstraintKinds #-}\r\n{-# LANGUAGE ExistentialQuantification #-}\r\n{-# LANGUAGE FlexibleContexts #-}\r\n{-# LANGUAGE FlexibleInstances #-}\r\n{-# LANGUAGE MultiParamTypeClasses #-}\r\n{-# LANGUAGE QuantifiedConstraints #-}\r\n{-# LANGUAGE TypeFamilies #-}\r\n{-# LANGUAGE UndecidableInstances #-}\r\nmodule Bug where\r\n\r\nimport Data.Kind\r\nimport Data.Proxy\r\n\r\nclass C a where\r\n m :: a -> ()\r\n\r\ndata Dict c = c => Dict\r\n\r\n-----\r\n\r\ntype family F a :: Type -> Type\r\nclass C (F a b) => CF a b\r\ninstance C (F a b) => CF a b\r\n\r\nworks1 :: (forall z. CF a z) => Proxy (a, b) -> Dict (CF a b)\r\nworks1 _ = Dict\r\n\r\nworks2 :: ( CF a b) => Proxy (a, b) -> Dict (C (F a b))\r\nworks2 _ = Dict\r\n\r\nworks3, fails :: (forall z. CF a z) => Proxy (a, b) -> Dict (C (F a b))\r\nworks3 p | Dict <- works1 p = Dict\r\nfails _ = Dict\r\n}}}\r\n\r\n`fails`, as its name suggests, fails to typecheck:\r\n\r\n{{{\r\n$ /opt/ghc/8.6.3/bin/ghc Bug.hs\r\n[1 of 1] Compiling Bug ( Bug.hs, Bug.o )\r\n\r\nBug.hs:33:11: error:\r\n • Could not deduce (C (F a b)) arising from a use of ‘Dict’\r\n from the context: forall z. CF a z\r\n bound by the type signature for:\r\n fails :: forall a b.\r\n (forall z. CF a z) =>\r\n Proxy (a, b) -> Dict (C (F a b))\r\n at Bug.hs:31:1-71\r\n • In the expression: Dict\r\n In an equation for ‘fails’: fails _ = Dict\r\n |\r\n33 | fails _ = Dict\r\n | ^^^^\r\n}}}\r\n\r\nBut I see no reason why this shouldn't typecheck. After all, the fact that `works1` typechecks proves that GHC's constraint solver is perfectly capable of deducing that `(forall z. CF a z)` implies `(CF a b)`, and the fact that `works2` typechecks proves that GHC's constraint solver is perfectly capable of deducing that `(CF a b)` implies that `(C (F a b))`. Why then can GHC's constraint solver not connect the dots and deduce that `(forall z. CF a z)` implies `(C (F a b))` (in the type of `fails`)?\r\n\r\nNote that something with the type `(forall z. CF a z) => Proxy (a, b) -> Dict (C (F a b))` //can// be made to work if you explicitly guide GHC along with explicit pattern-matching on a `Dict`, as `works3` demonstrates. But I claim that this shouldn't be necessary.\r\n\r\nMoreover, in this variation of the program above:\r\n\r\n{{{#!hs\r\n-- <as above>\r\n-----\r\n\r\ndata G a :: Type -> Type\r\nclass C (G a b) => CG a b\r\ninstance C (G a b) => CG a b\r\n\r\nworks1' :: (forall z. CG a z) => Proxy (a, b) -> Dict (CG a b)\r\nworks1' _ = Dict\r\n\r\nworks2' :: ( CG a b) => Proxy (a, b) -> Dict (C (G a b))\r\nworks2' _ = Dict\r\n\r\nworks3' :: (forall z. CG a z) => Proxy (a, b) -> Dict (C (G a b))\r\nworks3' _ = Dict\r\n}}}\r\n\r\n`works3'` needs no explicit `Dict` pattern-matching to typecheck.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16364Derived Enum for small number of constructors seems suboptimal2019-07-07T18:00:22ZMateusz KowalczykDerived Enum for small number of constructors seems suboptimal```hs
{-# LANGUAGE MagicHash #-}
module En (toEnum', toEnum'', toEnum''', toEnum'''') where
import GHC.Int
import GHC.Prim
import GHC.Word
data Q' = Foo' | Bar'
deriving Enum
toEnum' :: Int -> Q'
toEnum' 0 = Foo'
toEnum' 1 = Bar'
...```hs
{-# LANGUAGE MagicHash #-}
module En (toEnum', toEnum'', toEnum''', toEnum'''') where
import GHC.Int
import GHC.Prim
import GHC.Word
data Q' = Foo' | Bar'
deriving Enum
toEnum' :: Int -> Q'
toEnum' 0 = Foo'
toEnum' 1 = Bar'
toEnum' x = error $ "out of range " <> show x
toEnum'' :: Int -> Q'
toEnum'' x@(I# n) | x >= 0 && x <= 1 = tagToEnum# n
toEnum'' x = error $ "out of range " <> show x
toEnum''' :: Int -> Q'
toEnum''' x@(I# n) | x == 0 || x == 1 = tagToEnum# n
toEnum''' x = error $ "out of range " <> show x
toEnum'''' :: Int -> Q'
toEnum'''' x@(I# n) = case int2Word# n `leWord#` 1## of
0# -> error $ "out of range " <> show x
_ -> tagToEnum# n
```
For the derived `toEnum`, we get something as
```hs
-- RHS size: {terms: 19, types: 4, coercions: 0, joins: 0/0}
En.$w$ctoEnum [InlPrag=NOUSERINLINE[2]] :: Int# -> Q'
[GblId,
Arity=1,
Str=<S,U>,
Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 83 0}]
En.$w$ctoEnum
= \ (ww_s3Kl :: Int#) ->
case >=# ww_s3Kl 0# of {
__DEFAULT -> En.$wlvl ww_s3Kl;
1# ->
case <=# ww_s3Kl 1# of {
__DEFAULT -> En.$wlvl ww_s3Kl;
1# -> tagToEnum# @ Q' ww_s3Kl
}
}
-- RHS size: {terms: 6, types: 3, coercions: 0, joins: 0/0}
En.$fEnumQ'_$ctoEnum [InlPrag=NOUSERINLINE[2]] :: Int -> Q'
[GblId,
Arity=1,
Str=<S(S),1*U(U)>,
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
Tmpl= \ (w_s3Ki [Occ=Once!] :: Int) ->
case w_s3Ki of { I# ww1_s3Kl [Occ=Once] ->
En.$w$ctoEnum ww1_s3Kl
}}]
En.$fEnumQ'_$ctoEnum
= \ (w_s3Ki :: Int) ->
case w_s3Ki of { I# ww1_s3Kl -> En.$w$ctoEnum ww1_s3Kl }
```
Two comparisons to find out one thing! Contrast this with something like `toEnum'`:
```hs
toEnum'
= \ (ds_d3dp :: Int) ->
case ds_d3dp of { I# ds1_d3dr ->
case ds1_d3dr of ds2_X3dR {
__DEFAULT -> En.$wlvl1 ds2_X3dR;
0# -> En.Foo';
1# -> En.Bar'
}
}
```
Surely this seems better? But we don't even have to write out the constructors by hand in this case. `toEnum'''` actually produces the same code as `toEnum'`.
I also wrote `toEnum''''` which I had some hopes for but actually runs the slowest. I'm unsure why. Seems simple enough:
```hs
toEnum''''
= \ (x_a2Sd :: Int) ->
case x_a2Sd of { I# n_a2Se ->
case leWord# (int2Word# n_a2Se) 1## of {
__DEFAULT -> tagToEnum# @ Q' n_a2Se;
0# -> En.$wlvl4 n_a2Se
}
}
```
The point of this ticket is to consider whether it's not better to simply expand small number of constructors in a derived enumeration into a pattern match. In microbenchmark, `toEnum'` seems faster.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Derived Enum for small number of constructors seems suboptimal","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"{{{#!hs\r\n{-# LANGUAGE MagicHash #-}\r\nmodule En (toEnum', toEnum'', toEnum''', toEnum'''') where\r\n\r\nimport GHC.Int\r\nimport GHC.Prim\r\nimport GHC.Word\r\n\r\ndata Q' = Foo' | Bar'\r\n deriving Enum\r\n\r\ntoEnum' :: Int -> Q'\r\ntoEnum' 0 = Foo'\r\ntoEnum' 1 = Bar'\r\ntoEnum' x = error $ \"out of range \" <> show x\r\n\r\ntoEnum'' :: Int -> Q'\r\ntoEnum'' x@(I# n) | x >= 0 && x <= 1 = tagToEnum# n\r\ntoEnum'' x = error $ \"out of range \" <> show x\r\n\r\ntoEnum''' :: Int -> Q'\r\ntoEnum''' x@(I# n) | x == 0 || x == 1 = tagToEnum# n\r\ntoEnum''' x = error $ \"out of range \" <> show x\r\n\r\ntoEnum'''' :: Int -> Q'\r\ntoEnum'''' x@(I# n) = case int2Word# n `leWord#` 1## of\r\n 0# -> error $ \"out of range \" <> show x\r\n _ -> tagToEnum# n\r\n}}}\r\n\r\nFor the derived {{{toEnum}}}, we get something as\r\n{{{#!hs\r\n\r\n-- RHS size: {terms: 19, types: 4, coercions: 0, joins: 0/0}\r\nEn.$w$ctoEnum [InlPrag=NOUSERINLINE[2]] :: Int# -> Q'\r\n[GblId,\r\n Arity=1,\r\n Str=<S,U>,\r\n Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True,\r\n WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 83 0}]\r\nEn.$w$ctoEnum\r\n = \\ (ww_s3Kl :: Int#) ->\r\n case >=# ww_s3Kl 0# of {\r\n __DEFAULT -> En.$wlvl ww_s3Kl;\r\n 1# ->\r\n case <=# ww_s3Kl 1# of {\r\n __DEFAULT -> En.$wlvl ww_s3Kl;\r\n 1# -> tagToEnum# @ Q' ww_s3Kl\r\n }\r\n }\r\n\r\n-- RHS size: {terms: 6, types: 3, coercions: 0, joins: 0/0}\r\nEn.$fEnumQ'_$ctoEnum [InlPrag=NOUSERINLINE[2]] :: Int -> Q'\r\n[GblId,\r\n Arity=1,\r\n Str=<S(S),1*U(U)>,\r\n Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,\r\n WorkFree=True, Expandable=True,\r\n Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)\r\n Tmpl= \\ (w_s3Ki [Occ=Once!] :: Int) ->\r\n case w_s3Ki of { I# ww1_s3Kl [Occ=Once] ->\r\n En.$w$ctoEnum ww1_s3Kl\r\n }}]\r\nEn.$fEnumQ'_$ctoEnum\r\n = \\ (w_s3Ki :: Int) ->\r\n case w_s3Ki of { I# ww1_s3Kl -> En.$w$ctoEnum ww1_s3Kl }\r\n}}}\r\n\r\nTwo comparisons to find out one thing! Contrast this with something like {{{toEnum'}}}:\r\n{{{#!hs\r\ntoEnum'\r\n = \\ (ds_d3dp :: Int) ->\r\n case ds_d3dp of { I# ds1_d3dr ->\r\n case ds1_d3dr of ds2_X3dR {\r\n __DEFAULT -> En.$wlvl1 ds2_X3dR;\r\n 0# -> En.Foo';\r\n 1# -> En.Bar'\r\n }\r\n }\r\n}}}\r\n\r\nSurely this seems better? But we don't even have to write out the constructors by hand in this case. {{{toEnum'''}}} actually produces the same code as {{{toEnum'}}}.\r\n\r\nI also wrote {{{toEnum''''}}} which I had some hopes for but actually runs the slowest. I'm unsure why. Seems simple enough:\r\n{{{#!hs\r\ntoEnum''''\r\n = \\ (x_a2Sd :: Int) ->\r\n case x_a2Sd of { I# n_a2Se ->\r\n case leWord# (int2Word# n_a2Se) 1## of {\r\n __DEFAULT -> tagToEnum# @ Q' n_a2Se;\r\n 0# -> En.$wlvl4 n_a2Se\r\n }\r\n }\r\n}}}\r\n\r\nThe point of this ticket is to consider whether it's not better to simply expand small number of constructors in a derived enumeration into a pattern match. In microbenchmark, {{{toEnum'}}} seems faster.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/16363Modular constant folding2023-10-05T11:39:09ZSylvain HenryModular constant foldingThe following code (taken from #16329):
```hs
func :: Int -> IO Int
func n = foldM step 0 xs
where
xs = map (n+) [1,2,3]
step acc x =
case x `mod` 3 of
0 -> pure acc
1 -> pure $ acc + 1
...The following code (taken from #16329):
```hs
func :: Int -> IO Int
func n = foldM step 0 xs
where
xs = map (n+) [1,2,3]
step acc x =
case x `mod` 3 of
0 -> pure acc
1 -> pure $ acc + 1
2 -> pure $ acc + 2
func' n = foldl step 0 xs
where
xs = map (n+) [1,2,3]
step acc x =
case x `mod` 3 of
0 -> acc
1 -> acc + 1
2 -> acc + 2
```
is simplified to the following core code:
```hs
func n =
case n + 1 `mod` 3 of
0 -> case n + 2 `mod` 3 of
0 -> case n + 3 `mod` 3 of
0 -> pure 0
1 -> pure 1
2 -> pure 2
1 -> case n + 3 `mod` 3 of
0 -> pure 1
1 -> pure 2
2 -> pure 3
2 -> case n + 3 `mod` 3 of
0 -> pure 2
1 -> pure 3
2 -> pure 4
1 -> case n + 2 `mod` 3 of
0 -> case n + 3 `mod` 3 of
0 -> pure 1
1 -> pure 2
2 -> pure 3
1 -> case n + 3 `mod` 3 of
0 -> pure 2
1 -> pure 3
2 -> pure 4
2 -> case n + 3 `mod` 3 of
0 -> pure 3
1 -> pure 4
2 -> pure 5
2 -> case n + 2 `mod` 3 of
0 -> case n + 3 `mod` 3 of
0 -> pure 2
1 -> pure 3
2 -> pure 4
1 -> case n + 3 `mod` 3 of
0 -> pure 3
1 -> pure 4
2 -> pure 5
2 -> case n + 3 `mod` 3 of
0 -> pure 4
1 -> pure 5
2 -> pure 6
func' n =
join j2 w2 =
join j1 w1 =
case n + 3 `mod` 3 of
0 -> w1
1 -> w1 + 1
2 -> w1 + 2
in case n + 2 `mod` 3 of
0 -> jump j1 w2
1 -> jump j1 (w2 + 1)
2 -> jump j1 (w2 + 2)
in case n + 1 `mod` 3 of
0 -> jump j2 0
1 -> jump j2 1
2 -> jump j2 2
```
Case-folding with modular arithmetic should remove the nesting.