TcPlugins: newWanted discards the source location
When a plugin spins off a new Wanted constraint, using newWanted
, based on a constraint it can simplify, the source location for the constraint is discarded.
This happens because we have:
-- GHC.Tc.Plugin
newWanted :: CtLoc -> PredType -> TcPluginM CtEvidence
newWanted loc pty
= unsafeTcPluginTcM (TcM.newWanted (ctLocOrigin loc) Nothing pty)
-- GHC.Tc.Utils.TcMType
newWanted :: CtOrigin -> Maybe TypeOrKind -> PredType -> TcM CtEvidence
newWanted orig t_or_k pty
= do loc <- getCtLocM orig t_or_k
d <- if isEqPrimPred pty then HoleDest <$> newCoercionHole pty
else EvVarDest <$> newEvVar pty
return $ CtWanted { ctev_dest = d
, ctev_pred = pty
, ctev_nosh = WDeriv
, ctev_loc = loc }
-- GHC.Tc.Utils.Monad
getCtLocM :: CtOrigin -> Maybe TypeOrKind -> TcM CtLoc
getCtLocM origin t_or_k
= do { env <- getLclEnv
; return (CtLoc { ctl_origin = origin
, ctl_env = env
, ctl_t_or_k = t_or_k
, ctl_depth = initialSubGoalDepth }) }
That is, starting with the CtLoc
(which has the source span information we want), we keep only the CtOrigin
, and discard the rest. The typechecker environment is then obtained from the monadic environment with getLclEnv
in getCtLocM
.
In practice, in a typechecking plugin, when one wants the emitted Wanted to have the same source location, one must wrap the newWanted
call in setCtLocM
. This sets the correct typechecker environment that to be retrieved by getLcLEnv
.
If GHC.Tc.Plugin.newWanted
is going to discard the local typechecking environment, then it should clearly indicate so in its type signature by taking a CtOrigin
instead of a CtLoc
.
@rae @nfrisby Do either of you have opinions on how to design the API to avoid this problem? Also tagging @edsko as he has been running into this issue.