Skip to content

CoreLint claims join points inside casted expressions are invalid.

In core lint we have:

lintCoreExpr (Cast expr co)
  = do (expr_ty, ue) <- markAllJoinsBad   $ lintCoreExpr expr
       to_ty <- lintCastExpr expr expr_ty co
       return (to_ty, ue)

This seems bogus to me. Currently I see this tripping for this Core on a branch of mine:

      joinrec {
        $sgo2_s1jk [Occ=LoopBreaker, Dmd=SCS(C1(L))]
          :: (Maybe a_aTK ~R# Max a_aTK) -> [Max a_aTK] -> Max a_aTK
        [LclId[JoinId(2)(Just [~, !])],
         Arity=2,
         Str=<L><1L>,
         Unf=OtherCon []]
        $sgo2_s1jk (sg_s1el :: Maybe a_aTK ~R# Max a_aTK)
                   (sc_s1jl [Occ=Once1!] :: [Max a_aTK])
          = case sc_s1jl of {
              [] ->
                (Nothing @a_aTK) `cast` (sg_s1el :: Maybe a_aTK ~R# Max a_aTK);
              : y_s1jn [Occ=Once1!] ys_s1jo [Occ=Once2] ->
                case y_s1jn
                     `cast` (N:Max[0] <a_aTK>_N :: Max a_aTK ~R# Maybe a_aTK)
                of {
                  Nothing ->
                    ((jump $sgo2_s1jk @~(sg_s1el :: Maybe a_aTK ~R# Max a_aTK) ys_s1jo)
                     `cast` (N:Max[0] <a_aTK>_N :: Max a_aTK ~R# Maybe a_aTK))
                    `cast` (Sym (N:Max[0] <a_aTK>_N) :: Maybe a_aTK ~R# Max a_aTK);
                  Just ipv_s1jq [Occ=Once1] ->
                    ((jump $sgo1_s1jb
                        ipv_s1jq
                        @~(Sym (N:Max[0]) <a_aTK>_N :: Maybe a_aTK ~R# Max a_aTK)
                        ys_s1jo)
                     `cast` (N:Max[0] <a_aTK>_N :: Max a_aTK ~R# Maybe a_aTK))
                    `cast` (Sym (N:Max[0] <a_aTK>_N) :: Maybe a_aTK ~R# Max a_aTK)
                }
            }

The join points are still in obvious tail call position. We just coerce the result their result to a different type which is a no-op at runtime. This becomes very obvious if we look at the generated STG:

          $sgo1_s1j8 [Occ=LoopBreaker, Dmd=LCS(C1(C1(L)))]
            :: a_aUA
               -> (GHC.Maybe.Maybe a_aUA ~R# Data.Functor.Utils.Max a_aUA)
               -> [Data.Functor.Utils.Max a_aUA]
               -> Data.Functor.Utils.Max a_aUA
          [LclId[JoinId(3)(Just [~, ~, !])],
           Arity=3,
           Str=<L><L><1L>,
           Unf=OtherCon []] =
              \r [sc_s1j9 sg_s1fd sc1_s1ja]
                  case sc1_s1ja of {
                    [] -> GHC.Maybe.Just [sc_s1j9];
                    : y_s1jc [Occ=Once1!] ys_s1jd [Occ=Once3] ->
                        case y_s1jc of {
                          GHC.Maybe.Nothing ->
                              $sgo1_s1j8 sc_s1j9 GHC.Prim.coercionToken# ys_s1jd;
                          GHC.Maybe.Just ipv_s1jf ->
                              case GHC.Classes.>= $dOrd_s1j6 sc_s1j9 ipv_s1jf of {
                                GHC.Types.False ->
                                    $sgo1_s1j8 ipv_s1jf GHC.Prim.coercionToken# ys_s1jd;
                                GHC.Types.True ->
                                    $sgo1_s1j8 sc_s1j9 GHC.Prim.coercionToken# ys_s1jd;
                              };
                        };
                  };
          end Rec }

It also doesn't violate any of the join invariants. So I plan to just allow joins inside casts.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information