Skip to content

Wrong compilation of bang patterns

I have this function:

fn5 :: Int -> [T] -> Int
fn5 i [] = i
fn5 i (A : ts) = fn5 (i + 1) ts
fn5 !i (B : ts) = fn5 (i + 2) ts
fn5 i (C : ts) = fn5 0 ts

This function should only seq the int after seeing that head of the list is B. But this is the generated code: (desugar)

Rec {
-- RHS size: {terms: 64, types: 33, coercions: 0}
fn5 [Occ=LoopBreaker] :: Int -> [T] -> Int
[LclIdX, Str=DmdType]
fn5 =
  \ (i_ayA :: Int) (ds_d1Zb :: [T]) ->
    let {
      fail_d1Zn :: GHC.Prim.Void# -> Int
      [LclId, Str=DmdType]
      fail_d1Zn =
        \ _ [Occ=Dead, OS=OneShot] ->
          Control.Exception.Base.patError
            @ 'GHC.Types.PtrRepLifted
            @ Int
            "Main.hs:(41,1)-(44,25)|function fn5"# } in
    case ds_d1Zb of _ [Occ=Dead] {
      [] -> i_ayA;
      : ds_d1Zk ts_ayC ->
        case ds_d1Zk of _ [Occ=Dead] {
          __DEFAULT ->
            (\ _ [Occ=Dead, OS=OneShot] ->
               let {
                 fail_d1Zp :: GHC.Prim.Void# -> Int
                 [LclId, Str=DmdType]
                 fail_d1Zp =
                   \ _ [Occ=Dead, OS=OneShot] ->
                     case ds_d1Zb of _ [Occ=Dead] {
                       __DEFAULT -> fail_d1Zn GHC.Prim.void#;
                       : ds_d1Zm ts_ayG ->
                         case ds_d1Zm of _ [Occ=Dead] {
                           __DEFAULT -> fail_d1Zn GHC.Prim.void#;
                           C -> fn5 (GHC.Types.I# 0#) ts_ayG
                         }
                     } } in
               case i_ayA of i_XyO { __DEFAULT ->
               case ds_d1Zb of _ [Occ=Dead] {
                 __DEFAULT -> fail_d1Zp GHC.Prim.void#;
                 : ds_d1Zl ts_ayE ->
                   case ds_d1Zl of _ [Occ=Dead] {
                     __DEFAULT -> fail_d1Zp GHC.Prim.void#;
                     B -> fn5 (+ @ Int GHC.Num.$fNumInt i_XyO (GHC.Types.I# 2#)) ts_ayE
                   }
               }
               })
              GHC.Prim.void#;
          A -> fn5 (+ @ Int GHC.Num.$fNumInt i_ayA (GHC.Types.I# 1#)) ts_ayC
        }
    }
end Rec }

This code evaluates the list, and evaluates the int unless head of the list is A. I don't know why there's special case in A? In any case, this is wrong behavior as it forces the int in wrong times. As an example, this fails:

data T = A | B | C

fn5 :: Int -> [T] -> Int
fn5 i [] = i
fn5 i (A : ts) = fn5 (i + 1) ts
fn5 !i (B : ts) = fn5 (i + 2) ts
fn5 i (C : ts) = fn5 0 ts

main = print (fn5 undefined [C])

Tried with: GHC HEAD, 8.0.1.

Edited by Ömer Sinan Ağacan
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information