Skip to content

Specialising through specialised method calls (#19644)

Sebastian Graf requested to merge wip/T19644 into master

In #19644 (closed), we discovered that the ClassOp/DFun rules from Note [ClassOp/DFun selection] inhibit transitive specialisation in a scenario like

class C a where m :: Show b => a -> b -> ...; n :: ...
instance C Int where m = ... -- $cm :: Show b => Int -> b -> ...
f :: forall a b. (C a, Show b) => ...
f $dC $dShow = ... m @a $dC @b $dShow ...
main = ... f @Int @Bool ...

After we specialise f for Int, we'll see m @a $dC @b $dShow in the body of $sf. But before this patch, Specialise doesn't apply the ClassOp/DFun rule to rewrite to a call of the instance method for C Int, e.g., $cm @Bool $dShow. As a result, Specialise couldn't further specialise $cm for Bool.

There's a better example in Note [Specialisation modulo dictionary selectors].

This patch enables proper Specialisation, as follows:

  1. In the App case of specExpr, try to apply the CalssOp/DictSel rule on the head of the application
  2. Attach an unfolding to freshly-bound dictionary ids such as $dC and $dShow in bindAuxiliaryDict

NB: Without (2), (1) would be pointless, because lookupRule wouldn't be able to look into the RHS of $dC to see the DFun.

(2) triggered #21332 (closed), because the Specialiser floats around dictionaries without accounting for them in the SpecEnv's InScopeSet, triggering a panic when rewriting dictionary unfoldings.

Fixes #19644 (closed) and #21332 (closed).

Edited by Sebastian Graf

Merge request reports