Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC

Commits:

4 changed files:

Changes:

  • compiler/GHC/Tc/Solver/Equality.hs
    ... ... @@ -2980,15 +2980,30 @@ But it's not so simple:
    2980 2980
        we kick out g1. Now we have two constraints
    
    2981 2981
            [W] g1        : F a ~ a Int  (arising from (F a ~ a Int))
    
    2982 2982
            [W] g2{rw:g1} : F a ~ a Int  (arising from (F alpha ~ F a))
    
    2983
    -   If we end up with g2 in the inert set (not g1) we'll get a very confusing
    
    2984
    -   error message that we can solve (F a ~ a Int)
    
    2985
    -       arising from F a ~ F a
    
    2983
    +   If we solve `g1` from `g2` we end up with
    
    2984
    +     g1 := g2
    
    2985
    +     [W] g2{} : F a ~ a Int  (arising from (F alpha ~ F a))
    
    2986
    +   and hence (since alpha := a) we report that we can't solve (F a ~ a Int)
    
    2987
    +   arising from (F a ~ F a), which is extremely confusing. Moreover, it seems
    
    2988
    +   wrong to "solve" `g1` using `g2` when `g2` has itself been rewritten by `g1`!
    
    2986 2989
     
    
    2987 2990
        TL;DR: Better to hang on to `g1` (with no rewriters), in preference
    
    2988 2991
        to `g2` (which has a rewriter).
    
    2989 2992
     
    
    2990 2993
        See (WRW11) in Note [Wanteds rewrite Wanteds: rewriter-sets]
    
    2991 2994
        in GHC.Tc.Types.Constraint.
    
    2995
    +
    
    2996
    +   Note that the decision to prefer a constraint without rewriters over one that
    
    2997
    +   has rewriters can also have a /huge/ effect on performance. For instance, it
    
    2998
    +   avoids an **exponential** blow-up in the size of coercions produced when
    
    2999
    +   typechecking in T26426. In that program, we have coercions of the form:
    
    3000
    +
    
    3001
    +     co_i :: TaggedTypes as `Append` TaggedTypes '[ty]
    
    3002
    +          ~# TaggedTypes (as `Append` '[ty])
    
    3003
    +
    
    3004
    +   and each 'co_{i+1}' contains the previous 'co_i' twice. Without preferring
    
    3005
    +   Wanteds with no rewriters, we essentially end up inlining 'co_i' into 'co_{i+1}',
    
    3006
    +   which results in exponentially-sized proof terms, growing like O(2^i).
    
    2992 3007
     -}
    
    2993 3008
     
    
    2994 3009
     tryInertEqs :: EqCt -> SolverStage ()
    

  • compiler/GHC/Tc/Solver/FunDeps.hs
    ... ... @@ -1198,6 +1198,56 @@ Key point: equations that are not relevant do not need to be considered for fund
    1198 1198
       and [W] I alpha ~ Int |> g2
    
    1199 1199
       Here we definiteily want to take advantage of injectivity.
    
    1200 1200
     
    
    1201
    +(CF6) This machinery can also have a significant positive effect on the size of
    
    1202
    +  proof terms. For example (simplification of T26426):
    
    1203
    +
    
    1204
    +      type family (++) a b where { '[] ++ ys = ys; (x:xs) ++ ys = x : (xs ++ ys) }
    
    1205
    +      type family MapId a where { MapId '[] = '[]; MapId (x:xs) = x : MapId xs }
    
    1206
    +
    
    1207
    +      app :: (MapId xs ++ MapId ys ~ MapId (xs ++ ys)) => Proxy xs -> Proxy ys -> Proxy (xs ++ ys)
    
    1208
    +
    
    1209
    +      test :: Proxy [ty_1, ..., ty_n]
    
    1210
    +      test =   Proxy @'[ty_1]
    
    1211
    +         `app` Proxy @'[ty_2]
    
    1212
    +         ...
    
    1213
    +         `app` Proxy @'[ty_n]
    
    1214
    +
    
    1215
    +  Every `app` call gives rise to a Wanted of the form:
    
    1216
    +
    
    1217
    +    [W] MapId acc_i ++ MapId '[ty_i] ~ MapId (acc_i ++ '[ty_i])
    
    1218
    +
    
    1219
    +  while the overall result type gives us a Wanted of the form
    
    1220
    +
    
    1221
    +    [W] acc_n ++ '[ty_n] ~ [ty_1, ..., ty_n]
    
    1222
    +
    
    1223
    +  By using (CFFA) on this result Wanted, we deduce that we must have
    
    1224
    +
    
    1225
    +    acc_n ~ [ty_1, ..., ty_{n-1}]
    
    1226
    +
    
    1227
    +  which is a flat list. Repeating the process, (CFFA) allows us to deduce that
    
    1228
    +
    
    1229
    +    acc_i ~ [ty_1, ..., ty_{i-1}]
    
    1230
    +
    
    1231
    +  for all i. This allows the other Wanteds to be solved directly, giving rise to
    
    1232
    +  proof terms with the typical triangular O(n^2) shape
    
    1233
    +
    
    1234
    +    co_i = (O(i) proof that MapId acc_i ++ MapId '[ty_i] ~ acc_{i+1})
    
    1235
    +         ; (O(i) proof that acc_{i+1} ~ MapId (acc_i ++ '[ty_i]))
    
    1236
    +
    
    1237
    +  However, /without/ (CFFA), 'acc_i' is not unified with a flat list but is left
    
    1238
    +  as the nested application:
    
    1239
    +
    
    1240
    +    acc_i ~ (... (('[ty_1] ++ '[ty_2]) ++ '[ty_3]) ... ++ '[ty_{i-1}])
    
    1241
    +
    
    1242
    +  This means that 'MapId acc_i' is stuck until we reduce the above, which takes
    
    1243
    +  O(i^2) type family reduction steps, instead of O(i). The same applies to
    
    1244
    +  the other proof term involving 'MapId (acc_i ++ '[ty_i])'.
    
    1245
    +  Consequently, without (CFFA) the overall coercion size blows up to O(n^3).
    
    1246
    +
    
    1247
    +  The takeaway is that (CFFA) allows us to push in the (flat) result type,
    
    1248
    +  instead of relying on recursively built sub-proof terms, which brings down
    
    1249
    +  coercion sizes (in certain situations) from O(n^3) to O(n^2).
    
    1250
    +
    
    1201 1251
     Note [Cache-caused loops]
    
    1202 1252
     ~~~~~~~~~~~~~~~~~~~~~~~~~
    
    1203 1253
     It is very dangerous to cache a rewritten wanted family equation as 'solved' in
    

  • testsuite/tests/perf/compiler/T26426.hs
    1
    +{-# LANGUAGE DataKinds #-}
    
    2
    +{-# LANGUAGE TypeFamilies #-}
    
    3
    +module T26426 (
    
    4
    +  someTypes
    
    5
    +) where
    
    6
    +
    
    7
    +import Data.Kind (Type)
    
    8
    +import GHC.TypeLits (Symbol)
    
    9
    +
    
    10
    +type family Append (left :: [k]) (right :: [k]) :: [k] where
    
    11
    +  Append '[] right = right
    
    12
    +  Append (a : rest) right = a : Append rest right
    
    13
    +
    
    14
    +type family TaggedTypes (tags :: [(Symbol, Type)]) :: [Type] where
    
    15
    +  TaggedTypes '[] = '[]
    
    16
    +  TaggedTypes ('(_, typ) : rest) = typ : TaggedTypes rest
    
    17
    +
    
    18
    +data Types (types :: [(Symbol, Type)]) = Types
    
    19
    +
    
    20
    +mkTypes :: forall sym val. val -> Types '[ '(sym, val) ]
    
    21
    +mkTypes _ = Types
    
    22
    +
    
    23
    +appendTypes ::
    
    24
    +  -- This constraint is the one that causes the issue. If the next line is commented
    
    25
    +  -- out, then this module compiles quickly
    
    26
    +  Append (TaggedTypes left) (TaggedTypes right) ~ TaggedTypes (Append left right) =>
    
    27
    +  Types left -> Types right -> Types (Append left right)
    
    28
    +appendTypes _ _ = Types
    
    29
    +
    
    30
    +someTypes ::
    
    31
    +  Types
    
    32
    +    [ '("01", Int)
    
    33
    +    , '("02", Int)
    
    34
    +    , '("03", Int)
    
    35
    +    , '("04", Int)
    
    36
    +    , '("05", Int)
    
    37
    +    , '("06", Int)
    
    38
    +    , '("07", Int)
    
    39
    +    , '("08", Int)
    
    40
    +    , '("09", Int)
    
    41
    +    , '("10", Int)
    
    42
    +    , '("11", Int)
    
    43
    +    , '("12", Int)
    
    44
    +    , '("13", Int)
    
    45
    +    , '("14", Int)
    
    46
    +    , '("15", Int)
    
    47
    +    , '("16", Int)
    
    48
    +    ]
    
    49
    +
    
    50
    +someTypes =
    
    51
    +  mkTypes @"01"  1 `appendTypes`
    
    52
    +  mkTypes @"02"  2 `appendTypes`
    
    53
    +  mkTypes @"03"  3 `appendTypes`
    
    54
    +  mkTypes @"04"  4 `appendTypes`
    
    55
    +  mkTypes @"05"  5 `appendTypes`
    
    56
    +  mkTypes @"06"  6 `appendTypes`
    
    57
    +  mkTypes @"07"  7 `appendTypes`
    
    58
    +  mkTypes @"08"  8 `appendTypes`
    
    59
    +  mkTypes @"09"  9 `appendTypes`
    
    60
    +  mkTypes @"10" 10 `appendTypes`
    
    61
    +  mkTypes @"11" 11 `appendTypes`
    
    62
    +  mkTypes @"12" 12 `appendTypes`
    
    63
    +  mkTypes @"13" 13 `appendTypes`
    
    64
    +  mkTypes @"14" 14 `appendTypes`
    
    65
    +  mkTypes @"15" 15 `appendTypes`
    
    66
    +  mkTypes @"16" 16

  • testsuite/tests/perf/compiler/all.T
    ... ... @@ -87,6 +87,13 @@ test('T783',
    87 87
           ],
    
    88 88
           compile,[''])
    
    89 89
     
    
    90
    +test ('T26426'
    
    91
    +     , [ only_ways(['normal'])
    
    92
    +       , collect_compiler_stats('bytes allocated',4) ]
    
    93
    +     , compile
    
    94
    +     , ['']
    
    95
    +     )
    
    96
    +
    
    90 97
     test('T5321Fun',
    
    91 98
          [ only_ways(['normal']),  # no optimisation for this one
    
    92 99
            collect_compiler_runtime(2),