
I've been trying to make Conal's ConCat plugin work for polymorphic code, and am running into some problems with the ghc doing that, and I'd very much appreciate help with that. Background: I'm trying to get -dcore-lint to flag when my actual problem happens (has to do with dictionary construction, but it fails earlier with another problem, which I think comes from the simplifier. tl;dr: This transformation seems to me problematic: https://ghc-compiler-notes.readthedocs.io/en/latest/notes/compiler/simplCore... The docs for the transformation say that it makes this replacement: case a +# b of r -> …r… into let r = a +# b in …r… But this creates a let binding with an unlifted binder, which the linter does not like: <no location info>: warning: [RHS of ... :: Int#] The type of this binder is unlifted: ... Binder's type: Int# Arguably, this rule might expect the let to be inlined, but we're seeing that the let stands, and the linter complains. My immediate concern is getting around this problem somehow so I can run the linter on later output of the simplifier. Is there any way to do this? I.e. don't stop when the linter complains, somehow massage the rules to work better - see below. Any help would be much appreciated! (I'm using ghc 8.8.3.) More details: The ConCat code has this rule: "rebox2" [~0] (+#) = \ u# v# -> unboxI (addC (boxI u#, boxI v#)) It fires like this: Rule fired Rule: rebox_2 Module: (ConCat.Rebox) Before: GHC.Prim.+# ValArg 10# ValArg 1# After: (\ (u#_aM4G :: GHC.Prim.Int#) (v#_aM4H :: GHC.Prim.Int#) -> ConCat.Rebox.unboxI (ConCat.AltCat.addC @ (->) @ GHC.Types.Int (ConCat.Category.$fNumCat->a @ GHC.Types.Int GHC.Num.$fNumInt) (ConCat.Rebox.boxI u#_aM4G, ConCat.Rebox.boxI v#_aM4H))) 10# 1# Cont: Stop[BoringCtxt] GHC.Prim.Int# ... and comes out of the simplifier like this: let { n1_sM4V :: GHC.Prim.Int# [LclId, Unf=Unf{Src=<vanilla>, TopLvl=False, Value=False, ConLike=False, WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 110 0}] n1_sM4V = case ConCat.AltCat.addC @ (->) @ GHC.Types.Int (ConCat.Category.$fNumCat->a @ GHC.Types.Int GHC.Num.$fNumInt) (ConCat.Rebox.boxI 10#, ConCat.Rebox.boxI 1#) of { GHC.Types.I# i#_aM4S -> i#_aM4S } } in GHC.Types.I# (case ConCat.AltCat.addC @ (->) @ GHC.Types.Int (ConCat.Category.$fNumCat->a @ GHC.Types.Int GHC.Num.$fNumInt) (ConCat.Rebox.boxI 10#, ConCat.Rebox.boxI 1#) of { GHC.Types.I# i#_aM4S -> i#_aM4S }) } in ... Ironically, you can see that the simplifier already *has* inlined, just not elided the (now dead) let binding yet, before the linter gets to it. I've also attached a shorter source file with the relevant rules that triggers the linter, albeit with a different message. Richard Eisenberg, Gabor Greif, and Conal helped me get to this point. Many thanks to them! -- Regards, Mike {-# LANGUAGE MagicHash #-} {-# OPTIONS_GHC -frewrite-rules #-} {-# OPTIONS_GHC -ddump-rule-rewrites #-} {-# OPTIONS_GHC -ddump-rules #-} {-# OPTIONS_GHC -dcore-lint #-} {-# OPTIONS_GHC -ddump-simpl #-} module ConCatRules where import GHC.Prim import GHC.Int boxI :: Int# -> Int boxI = I# {-# INLINE [0] boxI #-} unboxI :: Int -> Int# unboxI (I# i#) = i# -- {-# INLINE [0] unboxI #-} plus :: Int -> Int -> Int plus x y = undefined {-# NOINLINE plus #-} {-# RULES "reboxa" forall u# v# . (+#) u# v# = unboxI (plus (boxI u#) (boxI v#)) "reboxb" forall u# . (+#) u# = \v# -> unboxI (plus (boxI u#) (boxI v#)) "reboxc" (+#) = \ u# v# -> unboxI (plus (boxI u#) (boxI v#)) #-} foo = I# (10# +# 1#)