Mixins and Sources

ghc-tcplugins-extra is a package with utilities for writing GHC typechecker plugins. It exposes one module and supports a lot of GHC versions!

examples/clash/ghc-tcplugins-extra.cabal
library
  exposed-modules:
      GHC.TcPluginM.Extra
  other-modules:
      Internal
  hs-source-dirs:
      src
  ghc-options: -Wall
  build-depends:
      base >=4.8 && <5
    , ghc >=7.10 && <9.13

In part, it deals with the changing GHC API with hs-source-dirs specific to GHC version ranges.

examples/clash/ghc-tcplugins-extra.cabal
    hs-source-dirs:
        src-ghc-tree-9.4
        src-ghc-9.12
    build-depends:
        ghc >=9.11 && <9.13

For older GHC versions, mixins are used as well:

examples/clash/ghc-tcplugins-extra.cabal
    hs-source-dirs:
        src-ghc-flat
        src-ghc-8.0
    build-depends:
        ghc >=8.0 && <8.2
    mixins:
        ghc hiding ()
      , ghc (TcRnTypes as Constraint)
      , ghc (Type as Predicate)

The package definition in package.dhall is a merger of the package fields from defaults.dhall and library fields resulting calls to version.dhall to set the hs-source-dirs, mixins and GHC version constraints.

examples/clash/package.dhall
let defs = ./defaults.dhall

let version = ./version.dhall

in  let ghc = { name = "ghc", mixin = [] : List Text }

    in  let gin =
                  ghc
              //  { mixin =
                    [ "hiding ()"
                    , "(TcRnTypes as Constraint)"
                    , "(Type as Predicate)"
                    ]
                  }

        in  let mods =
                  [ "GhcApi.Constraint"
                  , "GhcApi.Predicate"
                  , "GhcApi.GhcPlugins"
                  , "Internal.Type"
                  , "Internal.Constraint"
                  , "Internal.Evidence"
                  ]

            in      defs
                //  { library =
                      { source-dirs = "src"
                      , dependencies =
                        [ "base >=4.8 && <5", "ghc >=7.10 && <9.13" ]
                      , exposed-modules = "GHC.TcPluginM.Extra"
                      , other-modules = "Internal"
                      , when =
                        [ version "9.11" "9.13" [ "tree-9.4", "9.12" ] ghc mods
                        , version "9.10" "9.11" [ "tree-9.4", "9.10" ] ghc mods
                        , version "9.8" "9.10" [ "tree-9.4", "9.8" ] ghc mods
                        , version "9.4" "9.8" [ "tree-9.4", "9.4" ] ghc mods
                        , version "9.2" "9.4" [ "tree", "9.2" ] ghc mods
                        , version "9.0" "9.2" [ "tree", "9.0" ] ghc mods
                        , version "8.10" "9.0" [ "flat", "8.10" ] ghc mods
                        , version "8.8" "8.10" [ "flat", "8.8" ] gin mods
                        , version "8.6" "8.8" [ "flat", "8.6" ] gin mods
                        , version "8.4" "8.6" [ "flat", "8.4" ] gin mods
                        , version "8.2" "8.4" [ "flat", "8.2" ] gin mods
                        , version "8.0" "8.2" [ "flat", "8.0" ] gin mods
                        ]
                      }
                    }

As well as setting package fields, such as name and version, defaults.dhall also has some conditionals to vary the warnings enabled.

examples/clash/defaults.dhall
{ name = "ghc-tcplugins-extra"
, version = "0.5"
, synopsis = "Utilities for writing GHC type-checker plugins"
, description =
    ''
    Utilities for writing GHC type-checker plugins, such as
    creating constraints, with a stable API covering multiple
    GHC releases.''
, category = "Type System"
, author = "Christiaan Baaij"
, maintainer = "christiaan.baaij@gmail.com"
, copyright =
    ''
    Copyright © 2015-2016, University of Twente,
                                2017-2018, QBayLogic''
, github = "clash-lang/ghc-tcplugins-extra"
, license = "BSD2"
, license-file = "LICENSE"
, tested-with =
    "GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2, GHC == 9.2.8, GHC == 9.4.7, GHC == 9.6.6, GHC == 9.8.4, GHC == 9.10.1, GHC == 9.12.1"
, extra-source-files =
  [ "README.md", "CHANGELOG.md", "defaults.dhall", "package.dhall" ]
, ghc-options = [ "-Wall" ]
, flags.deverror
  =
  { description = "Enables `-Werror` for development mode and TravisCI"
  , default = False
  , manual = True
  }
, when =
  [ { condition = "impl(ghc >= 8.0.0)"
    , ghc-options =
      [ "-Wcompat"
      , "-Wincomplete-uni-patterns"
      , "-Widentities"
      , "-Wredundant-constraints"
      ]
    }
  , { condition = "impl(ghc >= 8.4.0)"
    , ghc-options = [ "-fhide-source-paths" ]
    }
  , { condition = "flag(deverror)", ghc-options = [ "-Werror" ] }
  ]
}

The version.dhall file is a function used to vary the hs-source-dirs and to constraint the GHC version within a GHC version range conditional.

examples/clash/version.dhall
let Prelude/List/map =
      https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map

in  \(low : Text) ->
    \(high : Text) ->
    \(srcs : List Text) ->
    \(ghc : { name : Text, mixin : List Text }) ->
    \(mods : List Text) ->
      { condition = "impl(ghc >= ${low}) && impl(ghc < ${high})"
      , source-dirs =
          Prelude/List/map Text Text (\(x : Text) -> "src-ghc-${x}") srcs
      , dependencies = [ ghc // { version = ">=${low} && <${high}" } ]
      , other-modules = mods
      }