Admin message

Due to a large amount of spam we do not allow new users to create repositories, they are "external" users. If you are a new user and want to create a repository, for example for forking GHC, open a new issue on ghc/ghc using the "get-verified" issue template

Mis-oriented <.> in mkWpFun_FRR builds ill-kinded coercion
<!-- ══════════════════════════════════════════════════════════════════ Draft metadata (for Simon — strip before filing) Covers GlaHiCo finding f1 of snippet 6142 (sweep group g171, backport b4f0eba7aba3 = master 8adfc22242b0, "Fix orientation in HsWrapper composition (<.>)"). Suggested labels: ~"T::bug" ~"typechecker" ~"DeepSubsumption" ~"RepPoly" ~"Core Lint" Suggested milestone: %9.15.1 (bug is on master); flag for 9.14.2 — the backport b4f0eba7aba3 is slated for 9.14.2 and turns code that 9.14.1 compiles cleanly into a Core Lint failure. Related: #26350 (fixed by the commit that introduces this), #26332, 56b32c5a2d5d / d44e8dbe24 (introduced mkWpFun_FRR + old <.> orientation; d44e8dbe24 shipped in 9.14.1) Reproducer: tickets/f1/ (Repro.hs, run.sh; verified 2026-08-06: master build 10.1.20260710 = d415f38a75 gives the Lint error; GHC 9.14.1 compiles cleanly, confirming the regression). The one-line fix suggested below is justified from the direction comments but has NOT been build-tested. ═══════════════════════════════════════════════════════════════════ --> ## Summary Commit 8adfc22242b0 ("Fix orientation in HsWrapper composition (`<.>`)", fixing #26350) changed the cast-composition rule to match the function-composition semantics of `<.>`: ```haskell WpCast c1 <.> WpCast c2 = WpCast (c2 `mkTransCo` c1) -- was: c1 ; c2 ``` It fixed the *outer* composition in `GHC.Tc.Utils.Unify.mkWpFun_FRR` (test T26350), but the *inner* composition in the same function is still written in the old, leftmost-applied-first orientation (`compiler/GHC/Tc/Utils/Unify.hs:2362` on master, `:2132` on ghc-9.14 with the backport b4f0eba7aba3): ```haskell arg_wrap_frr = mkWpCastN (mkSymCo exp_arg_co) <.> arg_wrap <.> mkWpCastN act_arg_co -- exp_arg_co :: exp_arg ~> exp_arg_frr -- act_arg_co :: act_arg ~> act_arg_frr -- arg_wrap :: exp_arg ~> act_arg -- arg_wrap_frr :: exp_arg_frr ~> act_arg_frr ``` Per the direction comments right next to it, the components are ``` mkWpCastN (mkSymCo exp_arg_co) :: exp_arg_frr ~> exp_arg arg_wrap :: exp_arg ~> act_arg mkWpCastN act_arg_co :: act_arg ~> act_arg_frr ``` and the required result is `arg_wrap_frr :: exp_arg_frr ~> act_arg_frr` (forced by its use in `mkWpFun arg_wrap_frr res_wrap ...`, whose `WpFun` desugaring applies `arg_wrap_frr` to the lambda binder of type `exp_arg_frr`). Since `<.>` composes like function composition — rightmost wrapper applied first, exactly what 8adfc222's new comment in `GHC.Tc.Types.Evidence` documents — the composition must be the mirror image: ```haskell arg_wrap_frr = mkWpCastN act_arg_co <.> arg_wrap <.> mkWpCastN (mkSymCo exp_arg_co) ``` As written, when `arg_wrap` is a `WpCast` and the `hasFixedRuntimeRep` coercions are non-reflexive, the old rule happened to produce the well-kinded `WpCast (sym exp_arg_co ; w ; act_arg_co)`; the fixed rule now produces `WpCast (act_arg_co ; w ; sym exp_arg_co)`, whose `TransCo` joins `w`'s RHS (`act_arg`) to `sym exp_arg_co`'s LHS (`exp_arg_frr`) — ill-kinded (`mkTransCo` does no kind checking), and rejected by Core Lint. So for this sub-case the fix trades one ill-kinded wrapper for another, regressing programs that GHC 9.14.1 compiles cleanly. The new T26350 test doesn't catch this because its types have syntactically fixed runtime representations: both FRR coercions are `Refl`, `mkWpCastN` collapses to `WpHole`, and the composition order is irrelevant. Triggering it needs DeepSubsumption where (a) eta-expansion is required (`needs_frr_checks`), and (b) the argument type's runtime rep is fixed only up to a non-trivial coercion, so `hasFixedRuntimeRep` returns non-`Refl` — which is precisely the situation this FRR code path exists to handle. ## Reproducer ```haskell {-# LANGUAGE DeepSubsumption, RankNTypes, PolyKinds, DataKinds, GADTs, TypeOperators, ScopedTypeVariables #-} module Repro where import GHC.Exts import Data.Type.Equality h :: forall r (a :: TYPE r) (b :: TYPE r). (r :~: LiftedRep) -> (a :~: b) -> () h Refl Refl = let v :: a -> (Int -> Int) -> Int v = undefined u :: b -> (forall c. c -> c) -> Int u = v in () ``` `u = v` needs deep subsumption. The result comparison `(Int -> Int) -> Int ≤ (forall c. c -> c) -> Int` requires a type application under a lambda, so `res_wrap` is not a cast and `mkWpFun_FRR` takes the `WpFun` path with FRR checks. The argument types `a`, `b :: TYPE r` have a fixed runtime rep only via the given `r ~ LiftedRep`, so both FRR coercions are non-`Refl` `GRefl` casts, and `arg_wrap` is the non-trivial cast `b ~ a` from the second given. With a master build containing 8adfc222 (10.1.20260710 = d415f38a75): ``` $ ghc -dcore-lint Repro.hs [1 of 1] Compiling Repro ( Repro.hs, Repro.o ) *** Core Lint errors : in result of Desugar (before optimization) *** Repro.hs:7:1: warning: Trans coercion mis-match: Sub co_atQ ; Sub (Sym (GRefl nominal b_atK (TYPE co_av3)_N)) b_atK ~ a_atJ (b_atK |> (TYPE co_av3)_N) ~ b_atK ... ``` The mismatched `TransCo` is exactly the mis-ordered composition: `co_atQ :: b ~# a` is `arg_wrap`'s coercion and is transitivity-composed with `sym exp_arg_co :: (b |> TYPE co) ~ b` — RHS `a` against LHS `b |> TYPE co`. GHC 9.14.1 (which has `mkWpFun_FRR` via d44e8dbe24 but the old `<.>` orientation) compiles the same file cleanly with `-dcore-lint`, so this is a regression introduced by 8adfc222 on master and by its backport b4f0eba7aba3 on ghc-9.14 (slated for 9.14.2). Without `-dcore-lint` compilation "succeeds" but produces the ill-kinded coercion in the desugared Core. <details><summary>Repro.hs</summary> ```haskell {-# LANGUAGE DeepSubsumption, RankNTypes, PolyKinds, DataKinds, GADTs, TypeOperators, ScopedTypeVariables #-} module Repro where import GHC.Exts import Data.Type.Equality h :: forall r (a :: TYPE r) (b :: TYPE r). (r :~: LiftedRep) -> (a :~: b) -> () h Refl Refl = let v :: a -> (Int -> Int) -> Int v = undefined u :: b -> (forall c. c -> c) -> Int u = v in () ``` </details> <details><summary>run.sh</summary> ```sh #!/bin/sh # Core Lint failure from mis-oriented arg_wrap_frr composition in mkWpFun_FRR. # Usage: GHC=/path/to/ghc sh run.sh # - GHC containing 8adfc22242b0 (master) / b4f0eba7aba3 (ghc-9.14): Lint error # - GHC 9.14.1 (pre-fix <.>): compiles cleanly : "${GHC:=ghc}" $GHC --version $GHC -dcore-lint -fforce-recomp Repro.hs ``` </details> ## Suggested fix Swap the composition (untested, but forced by the direction comments): ```haskell arg_wrap_frr = mkWpCastN act_arg_co <.> arg_wrap <.> mkWpCastN (mkSymCo exp_arg_co) ``` Side observation from the same analysis: when `arg_wrap` is *not* a hole/cast (e.g. contains a type application), the `WpCompose` desugaring applied the rightmost wrapper first even before 8adfc222, so that sub-case of the line appears to have been wrong already in 9.14.1; the swap above should fix both sub-cases. The reproducer above would make a reasonable regression test next to T26350. ## Provenance Found by [GlaHiCo](https://gitlab.haskell.org/sjakobi/GlaHiCo), an LLM-driven review pipeline, while reviewing the 9.14.2 backports; the published review of b4f0eba7aba3 (= master 8adfc22242b0) is at https://gitlab.haskell.org/sjakobi/GlaHiCo/-/snippets/6142 (finding f1). This draft was prepared by an LLM agent (which also built and ran the reproducer) and reviewed by a human before filing.
issue