Simon Jakobi pushed to branch wip/sjakobi/T27459 at Glasgow Haskell Compiler / GHC

Commits:

4 changed files:

Changes:

  • compiler/GHC/Core/RoughMap.hs
    ... ... @@ -168,6 +168,16 @@ each candidate. We only need the full list of unifiers when displaying error mes
    168 168
     Therefore the list is computed lazily so much work can be avoided constructing the
    
    169 169
     list in the first place.
    
    170 170
     
    
    171
    +For the same reason the unifiers are enumerated in non-deterministic order (see
    
    172
    +the RML_WildCard case of lookupRM'): a deterministic fold would have to inspect
    
    173
    +every entry of rm_known before it could produce the first unifier, defeating
    
    174
    +that laziness (#27459; see Note [Cost of deterministic iteration] in
    
    175
    +GHC.Types.Unique.DFM). The order is observable only where error messages are
    
    176
    +rendered, so those sites must sort the unifiers they display; see
    
    177
    +fuzzyClsInstCmp in GHC.Core.InstEnv and reportConflictInstErr in
    
    178
    +GHC.Tc.Instance.Family. The matches, by contrast, are still enumerated
    
    179
    +deterministically.
    
    180
    +
    
    171 181
     Note [Simple Matching Semantics]
    
    172 182
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    173 183
     Suppose `rm` is a RoughMap representing a set of (key,vals) pairs,
    
    ... ... @@ -420,15 +430,18 @@ lookupRM' (RML_NoKnownTc : tcs) rm =
    420 430
     
    
    421 431
     lookupRM' (RML_WildCard : tcs)    rm  =
    
    422 432
     --  pprTrace "RM wild" (ppr tcs $$ ppr (eltsDNameEnv (rm_known rm))) $
    
    423
    -  let (m, u)     = foldDNameEnv add_one (emptyBag, []) (rm_known rm)
    
    433
    +  let m = foldDNameEnv (\rm' acc -> fst (lookupRM' tcs rm') `unionBags` acc)
    
    434
    +                       emptyBag (rm_known rm)
    
    435
    +      -- The unifiers are enumerated non-deterministically: hot consumers
    
    436
    +      -- only test whether the list is empty, and the lazy fold lets that
    
    437
    +      -- test stop at the first unifier instead of paying for deterministic
    
    438
    +      -- iteration over the whole map (#27459).
    
    439
    +      -- See Note [Matches vs Unifiers].
    
    440
    +      u = nonDetFoldDNameEnv (\rm' acc -> snd (lookupRM' tcs rm') ++ acc)
    
    441
    +                             [] (rm_known rm)
    
    424 442
           (u_m, u_u) = lookupRM' tcs (rm_wild rm)
    
    425 443
       in ( rm_empty rm `unionBags` u_m `unionBags` m
    
    426 444
          , bagToList (rm_empty rm) ++ u_u ++ u )
    
    427
    -  where
    
    428
    -     add_one :: RoughMap a -> (Bag a, [a]) -> (Bag a, [a])
    
    429
    -     add_one rm ~(m2, u2) = (m1 `unionBags` m2, u1 ++ u2)
    
    430
    -                          where
    
    431
    -                            (m1,u1) = lookupRM' tcs rm
    
    432 445
     
    
    433 446
     unionRM :: RoughMap a -> RoughMap a -> RoughMap a
    
    434 447
     unionRM RMEmpty a = a
    

  • compiler/GHC/Tc/Instance/Family.hs
    ... ... @@ -939,11 +939,18 @@ buildInjectivityError mkErr fam_tc branches
    939 939
     reportConflictInstErr :: FamInst -> [FamInst] -> TcRn ()
    
    940 940
     reportConflictInstErr _ []
    
    941 941
       = return ()  -- No conflicts
    
    942
    -reportConflictInstErr fam_inst (conf_inst : _) =
    
    942
    +reportConflictInstErr fam_inst (conf_inst1 : conf_insts) =
    
    943
    +   -- The conflicts are enumerated in non-deterministic order (see
    
    944
    +   -- Note [Matches vs Unifiers] in GHC.Core.RoughMap), so pick the one to
    
    945
    +   -- report deterministically.
    
    943 946
        -- The sortBy just arranges that instances are displayed in order
    
    944 947
        -- of source location, which reduced wobbling in error messages,
    
    945 948
        -- and is better for users
    
    946
    -  let   sorted  = NE.sortBy (SrcLoc.leftmost_smallest `on` getSpan) (fam_inst NE.:| [conf_inst])
    
    949
    +  let   conf_inst = minimumBy cmp_inst (conf_inst1 :| conf_insts)
    
    950
    +        cmp_inst f1 f2 = case (SrcLoc.leftmost_smallest `on` getSpan) f1 f2 of
    
    951
    +                           EQ -> (stableNameCmp `on` (getName . famInstAxiom)) f1 f2
    
    952
    +                           o  -> o
    
    953
    +        sorted  = NE.sortBy (SrcLoc.leftmost_smallest `on` getSpan) (fam_inst NE.:| [conf_inst])
    
    947 954
             fi1     = NE.head sorted
    
    948 955
             span    = coAxBranchSpan (coAxiomSingleBranch (famInstAxiom fi1))
    
    949 956
             getSpan = getSrcSpan . famInstAxiom
    

  • compiler/GHC/Types/Name/Env.hs
    ... ... @@ -40,6 +40,7 @@ module GHC.Types.Name.Env (
    40 40
             plusDNameEnv_C,
    
    41 41
             foldDNameEnv,
    
    42 42
             nonDetStrictFoldDNameEnv,
    
    43
    +        nonDetFoldDNameEnv,
    
    43 44
             -- ** Dependency analysis
    
    44 45
             depAnal
    
    45 46
         ) where
    
    ... ... @@ -224,3 +225,7 @@ plusDNameEnv_C = plusUDFM_C
    224 225
     nonDetStrictFoldDNameEnv :: (a -> b -> b) -> b -> DNameEnv a -> b
    
    225 226
     nonDetStrictFoldDNameEnv = nonDetStrictFoldUDFM
    
    226 227
     
    
    228
    +-- | Lazy nondeterministic fold; can stream and short-circuit.
    
    229
    +nonDetFoldDNameEnv :: (a -> b -> b) -> b -> DNameEnv a -> b
    
    230
    +nonDetFoldDNameEnv = nonDetFoldUDFM
    
    231
    +

  • compiler/GHC/Types/Unique/DFM.hs
    ... ... @@ -66,6 +66,7 @@ module GHC.Types.Unique.DFM (
    66 66
             udfmToList,
    
    67 67
             udfmToUfm,
    
    68 68
             nonDetStrictFoldUDFM,
    
    69
    +        nonDetFoldUDFM,
    
    69 70
             unsafeCastUDFMKey,
    
    70 71
             alwaysUnsafeUfmToUdfm,
    
    71 72
         ) where
    
    ... ... @@ -378,6 +379,15 @@ nonDetStrictFoldUDFM k z (UDFM m _i) = foldl' k' z m
    378 379
       where
    
    379 380
         k' acc (TaggedVal v _) = k v acc
    
    380 381
     
    
    382
    +-- | Performs a nondeterministic lazy right fold over the UniqDFM.
    
    383
    +-- It's O(n), and lazy in the accumulator, so unlike 'foldUDFM' it can
    
    384
    +-- stream and short-circuit; see Note [Cost of deterministic iteration].
    
    385
    +-- If you use this please provide a justification why it doesn't introduce
    
    386
    +-- nondeterminism.
    
    387
    +nonDetFoldUDFM :: (elt -> a -> a) -> a -> UniqDFM key elt -> a
    
    388
    +{-# INLINE nonDetFoldUDFM #-}
    
    389
    +nonDetFoldUDFM k z (UDFM m _i) = M.foldr (k . taggedFst) z m
    
    390
    +
    
    381 391
     {- Note [Cost of deterministic iteration]
    
    382 392
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    383 393
     Deterministic iteration -- foldUDFM, eltsUDFM, udfmToList, and everything
    
    ... ... @@ -392,7 +402,8 @@ whether the result was non-empty.
    392 402
     
    
    393 403
     So: to test for emptiness, use isNullUDFM rather than null on eltsUDFM;
    
    394 404
     for order-oblivious queries, prefer short-circuiting anyUDFM/allUDFM; and
    
    395
    -if you don't need the deterministic order at all, use nonDetStrictFoldUDFM.
    
    405
    +if you don't need the deterministic order at all, use nonDetStrictFoldUDFM
    
    406
    +(or nonDetFoldUDFM when the fold should stream or short-circuit).
    
    396 407
     -}
    
    397 408
     
    
    398 409
     -- | Deterministic, in order of insertion.