[GHC] #15599: typeclass inference depends on whether a module is exposed.

#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Keywords: | Operating System: Linux Architecture: | Type of failure: Incorrect result Unknown/Multiple | at runtime Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- My first bug report for GHC: I've found some strange behavior in GHC 8.2.2 relating to typeclass inference. Essentially, for two identical modules, GHC infers for one of them that one typeclass instance applies, and for another that a different instance applies. The only language extensions involved are FlexibleInstances, MultiParamTypeClasses, GADTs, and ScopedTypeVariables. There are no INCOHERENT pragmas involved. The only difference between the two modules is that one of them (the one displaying correct typeclass inference) is an exposed module, while the other is not mentioned in the cabal file. The phenomenon affects other packages that import the original package---they display the incorrect behavior, rather than the correct behavior that the exposed module displays. The original discussion is here: [https://github.com/gleachkr/Carnap/issues/4] My best attempt at a minimal example can be found at [https://github.com/gleachkr/GHC-Repro]. You can run the "test.sh" script included there to see the phenomenon in action. I don't see this behavior in other GHC versions, but I'm told that bug reports for older GHC versions are welcome, so here I am. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Linux | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): There's a big indirection through stack and cabal here. e.g. how exactly this command invoke GHC, and what files exist at that moment? {{{ echo "test" | stack repl src/Tests/Good.hs -- 2> /dev/null | grep checkFlag }}} Would it be possible to explain how to repro by one or more invocations of GHC directly? Thanks -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Linux | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by gleachkr): Thanks for the quick reply. I've updated the repro repo with test-ghci.sh, which uses only ghci, but which demonstrates similar behavior. I did need to load the pkgdbs that stack generated. I've included those in the repo, in case they might help. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Linux | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): What's the `-package-db` stuff? I tried this {{{ #!/bin/bash GHCI822="/home/simonpj/5builds/ghc-8.2-branch/inplace/bin/ghc-stage2 --interactive" GHCI843="/home/simonpj/5builds/ghc-8.4-branch/inplace/bin/ghc-stage2 --interactive" echo "Behavior in 8.2.2 with pkgdb" echo "test" | $GHCI822 Good.hs 2> /dev/null | grep checkFlag echo "Behavior in 8.2.2 without pkgdb" echo "test" | $GHCI822 Good.hs Link.hs 2> /dev/null | grep checkFlag echo "Behavior in 8.4.3 with pkgdb" echo "test" | $GHCI843 Good.hs 2> /dev/null | grep checkFlag echo "Behavior in 8.4.3 without pkgdb" echo "test" | $GHCI843 Good.hs Link.hs 2> /dev/null | grep checkFlag }}} and got {{{ simonpj@cam-05-unx:~/tmp/T15599$ ./test-ghci.sh Behavior in 8.2.2 with pkgdb *Good> Flag {checkFlag = True} Behavior in 8.2.2 without pkgdb *Good> Flag {checkFlag = True} Behavior in 8.4.3 with pkgdb *Good> Flag {checkFlag = True} Behavior in 8.4.3 without pkgdb *Good> Flag {checkFlag = True} }}} This is with all the files in the same directory. With your file structure (source files nested inside `src/Tests`), the first command fails with {{{ Behavior in 8.2.2 with pkgdb GHCi, version 8.2.2.20180313: http://www.haskell.org/ghc/ :? for help [1 of 1] Compiling Tests.Good ( src/Tests/Good.hs, interpreted ) src/Tests/Good.hs:3:1: error: Could not find module ‘Tests.Link’ Use -v to see a list of the files searched for. | 3 | import Tests.Link | ^^^^^^^^^^^^^^^^^ Failed, no modules loaded. }}} Clearly I don't understand your use of package databases here -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Linux | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by gleachkr): Sorry, my mistake. it looks like the `-package-db` flag won't suffice to make this more portable and to disentangle it from stack. The included pkgdb directories refer back to the `.stack-work` directory, which isn't around unless you build the package with stack. Here's what I get when I run the two included scripts, though: {{{ GHC-Repro master ❯ ./test.sh Building project... These two results should be the same, since the only difference between the files is that one is an exported module λ ❯ Flag {checkFlag = True} λ ❯ Flag {checkFlag = False} Here it is again with 8.4.3: Building project... λ ❯ Flag {checkFlag = True} λ ❯ Flag {checkFlag = True} GHC-Repro master ❯ ./test-ghci.sh Behavior in 8.2.2 with pkgdb λ ❯ Flag {checkFlag = False} Behavior in 8.2.2 without pkgdb λ ❯ Flag {checkFlag = True} Behavior in 8.4.3 with pkgdb λ ❯ Flag {checkFlag = True} Behavior in 8.4.3 without pkgdb λ ❯ Flag {checkFlag = True} }}} When I run ghci as you did, with everything in the same directory (or with `-isrc`), I get the same results as you, `True` throughout. The difference that made me try the package-db route was that it seems (from a fair amount of experimentation) that you get `checkFlag=False` when the modules from GHC-Repro are not compiled by ghci, but just included, so when you get this loading message: {{{ [1 of 1] Compiling Tests.Good ( src/Tests/Good.hs, interpreted ) [Tests.Link changed] Ok, one module loaded. }}} rather than {{{ [1 of 2] Compiling Tests.Link ( src/Tests/Link.hs, interpreted ) [2 of 2] Compiling Tests.Good ( src/Tests/Good.hs, interpreted ) Ok, two modules loaded. }}} This suggested to me that `Tests.Link` needed to be available as part of a package rather than being loaded into ghci, which I think the second script confirms. In case it might be helpful, I've added the `.stack-work` directory to the github repo, and changed the paths on the `test-ghci.sh` script to point to the pkgdbs inside of that directory. I don't know how portable this is, though, (I hope it would run on other x86 linux machines, but I'm not sure) and it is pretty far from a clean reproduction. Do you know of a better approach? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

The difference that made me try the package-db route was that it seems (from a fair amount of experimentation) that you get checkFlag=False when
#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Linux | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): the modules from GHC-Repro are not compiled by ghci, but just included, What does "just included" mean? Can you give a sequence of ghc commands that demonstrates the problem? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Linux | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by gleachkr): By "just included", I meant "available in ghci as a package module". I hope that's clear enough---I've read the documentation, but I'm not a GHC developer, so my usage might be off here. The commands in `test-ghci.sh` demonstrate what I take to be the problem. Specifically, the command that gives `checkFlag=false` as the value of `test` from `Good.hs` is: `echo "test" | $GHC822 --interactive -package-db $PKGDB src/Tests/Good.hs`. It seems to generate something like this: {{{ GHC-Repro master ❯ echo "test" | ~/.stack/programs/x86_64-linux/ghc- nopie-8.2.2/bin/ghc --interactive -package-db ./.stack-work/install/x86_64 -linux-nopie/lts-11.15/8.2.2/pkgdb src/Tests/Good.hs GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help Loaded GHCi configuration from /home/graham/dotfiles/home/.ghci [1 of 1] Compiling Tests.Good ( src/Tests/Good.hs, interpreted ) Ok, one module loaded. λ ❯ Flag {checkFlag = False} λ ❯ Leaving GHCi. }}} The sticking point is that, as far as I can tell, the reproduction requires `Tests.Link` to be available as a package module. I'm not sure of the best way to make that happen on your end. I've tried including `.stack-work` in the repo, so that you could, after pulling the latest, hopefully run something like {{{ echo "test" | /home/simonpj/5builds/ghc-8.2-branch/inplace/bin/ghc-stage2 --interactive -package-db ./.stack-work/install/x86_64-linux- nopie/lts-11.15/8.2.2/pkgdb src/Tests/Good.hs }}} and get the same result as me. However, I'm not sure this will work, so if you have another way of including the contents of GHC-Repro as package modules on your end, that might be preferable. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Linux | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by AndreasK): For another data point: On windows: {{{ $ bash test.sh Building project... These two results should be the same, since the only difference between the files is that one is an exported module *Tests.Good> Flag {checkFlag = True} *Tests.Bad> Flag {checkFlag = False} Here it is again with 8.4.3: Building project... *Tests.Bad> Flag {checkFlag = True} *Tests.Good> Flag {checkFlag = True} }}} The ghci script is hardcoded to linux paths so didn't work on windows. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#15599: typeclass inference depends on whether a module is exposed. -------------------------------------+------------------------------------- Reporter: gleachkr | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.2.3 Component: Compiler | Version: 8.2.2 Resolution: | Keywords: Operating System: Linux | Architecture: Type of failure: Incorrect result | Unknown/Multiple at runtime | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by mpickering): Here's how to reproduce it without any of these package db gubbins. 1. Clone `https://github.com/gleachkr/GHC-Repro.git` 2. `echo "test" | cabal repl` - observe that `Flag {checkFlag = True}` 3. `cabal install .` 4. `echo "test" | ghci src/Test/Good.hs` - observe that `Flag {checkFlag = False}` So the same module used in two different ways uses two different instances. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/15599#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC