Weird behaviour with `tcIfaceExpr`
When recovering the Core AST of a class method in a plugin through multiple methods, the type-check loaded (deserialised) AST appears to be using the wrong expression for certain methods. This occurs both using ASTs recovered from the pre-existing unfoldings, as well as when using the toIfaceBind
and tcIfaceExpr
functions from GHC to (de)serialise the bindings via an extensible interface field.
As an example, using the following type class and instances:
class TwoClass a where
twoA :: a -> Integer
twoB :: a -> Bool
instance TwoClass Integer where
twoA = id
twoB = (>1)
instance TwoClass Bool where
twoA True = 1
twoA False = 0
twoB = not
Before serialisation, from the CgGuts.cgBinds
, we have class methods that look like:
twoA :: forall a. TwoClass a => a -> Integer
[GblId[ClassOp],
Arity=1,
Caf=NoCafRefs,
Str=<SP(SL,A)>,
RULES: Built in rule for twoA: "Class op twoA"]
twoA
= \ (@a) (v_B1 :: TwoClass a) ->
case v_B1 of v_B1 { C:TwoClass v_B2 v_B3 -> v_B2 },
twoB :: forall a. TwoClass a => a -> Bool
[GblId[ClassOp],
Arity=1,
Caf=NoCafRefs,
Str=<SP(A,SL)>,
RULES: Built in rule for twoB: "Class op twoB"]
twoB
= \ (@a) (v_B1 :: TwoClass a) ->
case v_B1 of v_B1 { C:TwoClass v_B2 v_B3 -> v_B3 }
Each of the class methods is deconstructed as a data constructor and obviously uses the correct field of that constructor as the method. However, after round-tripping this through (de)serialisation, we're have:
twoA :: forall a. TwoClass a => a -> Integer
[LclId]
twoA
= \ (@a) (v :: TwoClass a) -> case v of v { C:TwoClass v v -> v },
twoB :: forall a. TwoClass a => a -> Bool
[LclId]
twoB
= \ (@a) (v :: TwoClass a) -> case v of v { C:TwoClass v v -> v }
Now, the reuse of the variable name v
shouldn't be a problem on it's own - since these local variables are serialised as FastStrings
, which have Unique
s - but we find in the plugin that for twoA
, it's the wrong Unique
, incorrectly giving twoA
an expression of type a -> Bool
.
We're using GHC 8.10.4 for the Plutus plugin, but I've tested and found what seems to be the same behaviour in an up-to-date version of master. I expect that there must be another explanation here, since unfoldings are used by GHC for inlining, and I don't believe those would go unnoticed if broken.