Skip to content

Update to GHC 9.2.2#4326

Closed
hdgarrood wants to merge 11 commits intopurescript:masterfrom
hdgarrood:update-ghc-9
Closed

Update to GHC 9.2.2#4326
hdgarrood wants to merge 11 commits intopurescript:masterfrom
hdgarrood:update-ghc-9

Conversation

@hdgarrood
Copy link
Copy Markdown
Contributor

@hdgarrood hdgarrood commented May 15, 2022

This PR updates us to GHC 9.2.2. Most of the updates are fairly straightforward; I will explain why I've made them as inline review comments.

The main reasons I think we might want to do this are:

  • to benefit from numerous performance enhancements in GHC in the 9.2 series (and the upcoming 9.4 series as well); see the release notes. I think these performance enhancements will mean that GHC can compile the PureScript compiler more quickly, but I don't think we would expect to see a speedup in the performance of the PureScript compiler itself.
  • to be able to provide ARM binaries for systems like M1 macs: as of version 9.2.1, GHC has a native ARM code generator.

Reasons not to merge this yet:

  • We depend on protolude-0.3.1 which is tagged but not yet uploaded to Hackage so for now I'm using a git reference in stack.yaml; this means that people would probably struggle to compile the PureScript compiler with cabal if we made a release with these changes. We should probably either drop the protolude dependency or wait for 0.3.1 to be uploaded to Hackage.
  • Weeder does not yet compile on GHC 9.2 Weeder 2.4.0, which targets GHC 9.2, has just been released
  • I should probably figure out what the deal with this warning is. I'm fairly sure it's a false positive as we aren't actually using the GHC API anywhere (AFAIK???)
    Warning:
        This package indirectly depends on multiple versions of the same package. This is very likely to cause a compile failure.
          package typed-process (typed-process-0.2.8.0-qJ7FQLjAUsDoh5UIGjmGT) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package streaming-commons (streaming-commons-0.2.2.4-8nDHmhtmpx83qtrdduE76B) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package sourcemap (sourcemap-0.1.7-9a6OzM8XbZDSeQz7MTa1o) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package purescript (purescript-0.15.1) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package purescript (purescript-0.15.1) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package purescript (purescript-0.15.1) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package optparse-applicative (optparse-applicative-0.17.0.0-G8nAkP3cjJUHOGraopmgpx) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package haskeline (haskeline-0.8.2-27iD1wLo6nE3EGXBbzNrZN) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package gitrev (gitrev-1.3.1-5EZyLHF9iyU5HR4ImcQtFa) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package conduit-extra (conduit-extra-1.3.6-IWwDkCT2NsHEPOAoybwv54) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package Cabal (Cabal-3.6.3.0-FskfNehIkKSJXUcrlACH2g) requires process-1.6.13.1-1ayluMYLS1yTV7wv3m4fy
          package ghc (ghc-9.2.2) requires process-1.6.13.2
    

- # If upgrading the Haskell image, also upgrade it in the lint job below
os: "ubuntu-latest"
image: "haskell:8.10.7-stretch@sha256:100f8fb7d7d8d64adb5e106fe8136b8d4cbdc03aeb2cbd145a7597d74b69bafb"
image: "haskell:9.2.2-buster@sha256:c2f489a95be8dd0b253da6980420a6e9c02e81c2d14838ca774f86f5b5db91f4"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buster (Debian 10) is the next Debian release after stretch. There is no stretch image which includes GHC 9.2.2, probably because stretch will stop receiving security updates next month (June 2022).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this would mean bumping our glibc dependency from 2.24 to 2.28.

Should we make a Discourse post asking if people would object to that? Seems like we consistently stir up trouble whenever this changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, good point. This certainly isn’t ideal. Maybe we should just take a basic Debian stretch image and install the Haskell tools ourselves? My inclination is to avoid bumping this if we can manage it.

| $(GitRev.gitDirty) = " DIRTY"
| otherwise = ""
dirty =
if $(GitRev.gitDirty)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before this change, GHC would complain that the otherwise case was redundant if GitRev.gitDirty evaluated to True.

deriving (Show, Eq, Ord, Foldable, Functor, Traversable)

$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''NameSource)
$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''ExportSource)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This (and a few other JSON instance rearrangements) were necessary because any instances defined below a TH deriveJSON call like this one won't be visible to that call, so if a data type A references another data type B in its definition, then the deriveJSON for B has to come before the one for A.

properName n = ProperName (N.coerceProperName <$> n)

getProperName :: forall a. ProperName -> Name (N.ProperName a)
getProperName pn = _getProperName pn -- eta expansion needed here due to simplified subsumption
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this change, you get an error like:

src\Language\PureScript\CST\Utils.hs:47:17: error:
    * Couldn't match type: forall (a1 :: N.ProperNameType).
                           Name (N.ProperName a1)
                     with: Name (N.ProperName a)
      Expected: ProperName -> Name (N.ProperName a)
        Actual: ProperName
                -> forall (a :: N.ProperNameType). Name (N.ProperName a)
    * In the expression: _getProperName
      In an equation for `getProperName': getProperName = _getProperName
    * Relevant bindings include
        getProperName :: ProperName -> Name (N.ProperName a)
          (bound at src\Language\PureScript\CST\Utils.hs:47:1)
   |
47 | getProperName = _getProperName
   |                 ^^^^^^^^^^^^^^

constructorTypeToJSON SumType = toJSON "SumType"

infixr 8 .=
(.=) :: ToJSON a => String -> a -> Pair
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost everything in this module is due to aeson-2 changes, specifically the left hand side of .= must now be a Key rather than a Text. I thought it might be easier to define our own version of .= so that we don't have to convert the key to a different type each time we call it.

go jss | not (any isReturn jss) = jss
| otherwise = let (body, ret : _) = break isReturn jss in body ++ [ret]
go jss =
case break isReturn jss of
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change was necessitated by the fact that -Wincomplete-uni-patterns was added to -Wall at some point between 8.10.7 and 9.2.2; the let (body, ret : _) = ... is an incomplete pattern because it does not account for what happens if the second element of the tuple is an empty list. Thankfully we can avoid it (as well as an unnecessary traversal of the list) by rewriting the function to use break instead.

let (x, a : y) = splitAt i l
in x ++ [t a] ++ y
updateAtFirstOrPrepend predicate update def xs =
case break predicate xs of
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another case where using break solves both a -Wincomplete-uni-patterns warning and also removes an unnecessary traversal of the list at the same time. I thought I'd take the opportunity to use clearer argument names here too.

let ImportRecord (Qualified (Just mnNew) _) mnOrig _ _ = head byOrig
in return (mnNew, mnOrig)
case head byOrig of
ImportRecord (Qualified (Just mnNew) _) mnOrig _ _ ->
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another -Wincomplete-uni-patterns warning

-- | Check that a newtype has just one data constructor with just one field, or
-- throw an error. If the newtype is valid, this function returns the single
-- data constructor declaration and the single field, as a 'proof' that the
-- newtype was indeed a valid newtype.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning the decl and the field here means that we avoid an unsafe pattern match in Sugar/TypeClasses/Deriving.

hdgarrood added 3 commits May 16, 2022 01:02
- Allow -Wincomplete-uni-patterns warnings in tests
- Compare the graph fixture as a JSON Value so that the ordering doesn't
  matter
- define and use `tails1` in TypeChecker.Entailment to make
  the validity of the non-emptiness assumption more obvious
- Bump to stack 2.7.5 in CI (to match the 9.2.2 Docker image)
dicts
-- process instances in a chain in index order
let found = for (init $ tails chain) $ \(tcd:tl) ->
let found = for (tails1 chain) $ \(tcd :| tl) ->
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another -Wincomplete-uni-patterns warning. This was safe before, but now the safety is tracked in the types.

Right res ->
let textRes = Text.decodeUtf8 $ ByteString.toStrict $ Json.encode res
in graphFixture `shouldBe` textRes
res `shouldBe` graphFixture
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change means that we don't have to update the fixture if the order of fields changes, and we don't get errors if the fields end up in different orders due to different build configurations. Updating aeson seems to have caused the fields in the result to end up in a different order.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, you're supposed to put the expected value second. The error message describes the 'expected' vs 'actual' value, so the error can be misleading if you put the expected value first; this is why I've flipped them around.

@hdgarrood
Copy link
Copy Markdown
Contributor Author

Seems like CI time for this branch is hovering around 14-15 mins, which might be slightly faster than it is currently (usually 15-18 mins from the looks of things), but the variance seems quite high so it's hard to tell.

@hdgarrood
Copy link
Copy Markdown
Contributor Author

I've created #4336, which covers a part of this (the new warnings) that can be merged now. As for the rest, I am inclined to wait until the upstream dependencies (weeder and protolude) are ready, so I think I'll close this for now.

@JordanMartinez
Copy link
Copy Markdown
Contributor

Looks like Weeder got updated to 9.2: https://github.com/ocharles/weeder/releases/tag/2.4.0

@hdgarrood
Copy link
Copy Markdown
Contributor Author

So now that protolude has been updated I think the only remaining task is to figure out why cabal thinks PureScript depends on the GHC API. If you try building PureScript with cabal instead of stack, it tries to compile the GHC API and fails. I think I might write something up and ask on the Cabal issue tracker or something, because this is quite strange to me.

@arrowd
Copy link
Copy Markdown
Contributor

arrowd commented Jun 7, 2022

If you try building PureScript with cabal instead of stack, it tries to compile the GHC API and fails

What package, exactly?

@hdgarrood
Copy link
Copy Markdown
Contributor Author

ghc

@arrowd
Copy link
Copy Markdown
Contributor

arrowd commented Jun 7, 2022

Can't reproduce this on my side. I just successfully compiled the code from this PR.

@hdgarrood
Copy link
Copy Markdown
Contributor Author

Interesting 🤔

@JordanMartinez JordanMartinez mentioned this pull request Jun 8, 2022
5 tasks
@hdgarrood hdgarrood deleted the update-ghc-9 branch September 23, 2022 14:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants