Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 5,344
    • Issues 5,344
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 571
    • Merge requests 571
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell CompilerGlasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #23052
Closed
Open
Issue created Feb 28, 2023 by Edsko de Vries@edsko

Plugin order is reversed in ghc 9.4

Summary

Plugin order is important, because the output of one plugin can feed into another plugin. The GHC manual says that "Plugins are loaded in order". However, this order seems to have been reversed in ghc 9.4: prior to 9.4, plugins were loaded in reverse order to how they appear in OPTIONS_GHC, whereas in 9.4 they are in order. This means that CPP may now be required (in code that supports multiple ghc versions) to correctly load multiple plugins.

Steps to reproduce

Consider this simple plugin code that adds some suffix to every string literal in a module:

{-# LANGUAGE CPP   #-}
{-# LANGUAGE GADTs #-}

module Plugin (Plugin, pluginWithSuffix) where

import Data.Data
import GHC.Plugins
import GHC.Hs

pluginWithSuffix :: String -> Plugin
pluginWithSuffix suffix = defaultPlugin {
      parsedResultAction = \_ _ -> return .
        ignoreMessages (modifyStrings suffix)
    }
  where
#if __GLASGOW_HASKELL__ >= 904
    ignoreMessages f (ParsedResult modl msgs) = ParsedResult (f modl) msgs
#else
    ignoreMessages = id
#endif

modifyStrings :: String -> HsParsedModule -> HsParsedModule
modifyStrings suffix m@HsParsedModule{hpm_module} =
    m{hpm_module = go hpm_module}
  where
    go :: forall a. Data a => a -> a
    go x =
        case (isHsExpr x, x) of
          (Just Refl, HsLit e1 (HsString e2 str)) ->
            HsLit e1 (HsString e2 (mappend str (fsLit suffix)))
          _otherwise ->
            gmapT go x

    isHsExpr :: forall a. Data a => a -> Maybe (a :~: HsExpr GhcPs)
    isHsExpr _ = eqT

We can then define 3 plugins with different suffices; A:

module PluginA (plugin) where

import Plugin

plugin :: Plugin
plugin = pluginWithSuffix"A"

B:

module PluginB (plugin) where

import Plugin

plugin :: Plugin
plugin = pluginWithSuffix "B"

and C:

module PluginC (plugin) where

import Plugin

plugin :: Plugin
plugin = pluginWithSuffix "C"

Then here is a simple test:

{-# OPTIONS_GHC -fplugin=PluginA #-}
{-# OPTIONS_GHC -fplugin=PluginB #-}
{-# OPTIONS_GHC -fplugin=PluginC #-}

module Main (main) where

main :: IO ()
main = putStrLn "Hi"

It doesn't matter if these are separate OPTIONS_GHC pragmas or a single one.

Expected behavior

Running the above code with ghc 9.2 gives

HiCBA

whereas in ghc 9.4 it gives

HiABC

Environment

  • GHC version used: ghc 9.2.7, ghc 9.4.4
Edited Feb 28, 2023 by Edsko de Vries
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking