#11731: Demand analysis: Thunk wrongly determined single-entry -------------------------------------+------------------------------------- Reporter: nomeata | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by nomeata): {{{ Entries Alloc Alloc'd #Alloc Single Multiple Non- void Arguments STG Name 4096 0 65536 2048 0 2048 0 sat_s2vw{v} (main@main:GamtebMain) (thk,se) in r2uq }}} The relevant `-ddump-prep` code is this: {{{ let { sat_s2vw [Occ=Once, Dmd=<L,1*U(U)>] :: GamtebType.Random [LclId, Str=DmdType] = \s srt:SRT:[r4K :-> Utils.$wgenRand] [] case Utils.$wgenRand w_s2ux of _ [Occ=Dead] { (#,#) ww5_s2vu [Occ=Once] _ [Occ=Dead] -> ww5_s2vu; }; } in TransPort.$wtransPort lvl2_r2ut lvl2_r2ut lvl2_r2ut lvl2_r2ut lvl1_r2us lvl2_r2ut lvl1_r2us w1_s2uz ww2_s2vk lvl_r2ur sat_s2vw ww17_s2vn ww19_s2vp ww22_s2vs; }}} The relevant code for `$wtransPort` ist {{{ TransPort.$wtransPort [InlPrag=[0], Occ=LoopBreaker] :: GamtebType.Coord -> GamtebType.Coord -> GamtebType.Coord -> GamtebType.Coord -> GamtebType.Coord -> GamtebType.Coord -> GamtebType.Weight -> GamtebType.Energy -> GamtebType.Indx -> GHC.Types.Int -> GamtebType.Random -> GamtebType.Prob -> GamtebType.Prob -> GHC.Prim.Double# -> (# [GamtebType.Result], [GamtebType.Stat] #) [GblId, Arity=14, Str=DmdType <L,U(U)><L,U(U)><L,U(U)><L,U(U)><L,U(U)><L,U(U)><L,U(U)><L,U(U)><L,U><L,U(U)><L,1*U(U)><L,U(U)><L,U(U)><S,U>, Unf=OtherCon []] = \r srt:SRT:[r4K :-> Utils.$wgenRand, r5x :-> Compton.$wcompton, r5O :-> Pair.$wpair, r3Df :-> TransPort.$wtransPort, r3Dr :-> lvl11_r3Dr] [ww_s3Dy ww1_s3Dz ww2_s3DA ww3_s3DB ww4_s3DC ww5_s3DD ww6_s3DE ww7_s3DF ww8_s3DG ww9_s3DH ww10_s3DI ww11_s3DJ ww12_s3DK ww13_s3DL] case Utils.$wgenRand ww10_s3DI of _ [Occ=Dead] { (#,#) ww15_s3DN [Occ=Once!] ww16_s3DO -> }}} Note how the strictness signature say that the `Random` argument is used at most once (`1*U(U)`). The call to `$wgenRand` is indeed the only use of `ww10_s3DI`. So here is the code of `$wgenRand`: {{{ Utils.$wgenRand [InlPrag=[0]] :: GamtebType.Random -> (# GamtebType.Random, GamtebType.Random #) [GblId, Arity=1, Str=DmdType <L,U(U)>, Unf=OtherCon []] = \r srt:SRT:[015 :-> GHC.Integer.Type.timesInteger, 017 :-> GHC.Integer.Type.negateInteger, 01j :-> GHC.Integer.Type.divInteger, 01x :-> GHC.Integer.Type.shiftLInteger] [w_s3BX] let { sat_s3CT [Occ=Once] :: GamtebType.Random [LclId, Str=DmdType] = \u srt:SRT:[015 :-> GHC.Integer.Type.timesInteger, 017 :-> GHC.Integer.Type.negateInteger, 01j :-> GHC.Integer.Type.divInteger, 01x :-> GHC.Integer.Type.shiftLInteger] [] case w_s3BX of _ [Occ=Dead] { GHC.Types.D# y_s3Cs [Occ=Once] -> ... }; } in let { sat_s3Cq [Occ=Once] :: GamtebType.Random [LclId, Str=DmdType] = \u srt:SRT:[015 :-> GHC.Integer.Type.timesInteger, 017 :-> GHC.Integer.Type.negateInteger, 01j :-> GHC.Integer.Type.divInteger, 01x :-> GHC.Integer.Type.shiftLInteger] [] case w_s3BX of _ [Occ=Dead] { GHC.Types.D# y_s3BZ [Occ=Once] -> ... }; } in (#,#) [sat_s3Cq sat_s3CT]; }}} So `$wgenRand` may evaluate its argument more than once (as its strictness signature says). On what grounds does `$wtransPort` then claim the argument is used at most once? Now if the argument to `$wgenRand` were a complex expression, this would be valid reasoning, as it would be let-bound and then shared. But trivial expressions, when passed as arguments, are _not_ shared at this point, so the information that the argument may be used multiple times should be propagated out. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11731#comment:1> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler