classifyTyCons :: UniqFM Bool                     -- ^type constructor conversion status
               -> [TyCon]                         -- ^type constructors that need to be classified
               -> ([TyCon], [TyCon], [TyCon])     -- ^tycons to be converted & not to be converted
classifyTyCons convStatus tcs = classify [] [] [] convStatus (tyConGroups tcs)
  where
    classify conv keep ignored _  [] = (conv, keep, ignored)
    classify conv keep ignored cs ((tcs, ds) : rs)
      | can_convert && must_convert
      = classify (tcs ++ conv) keep ignored (cs `addListToUFM` [(tc, True) | tc <- tcs]) rs
      | can_convert
      = classify conv (tcs ++ keep) ignored (cs `addListToUFM` [(tc, False) | tc <- tcs]) rs
      | otherwise
      = classify conv keep (tcs ++ ignored) cs rs
      where
        refs = ds `delListFromUniqSet` tcs

        can_convert  = (isNullUFM (refs `minusUFM` cs) && all convertable tcs)
                       || isShowClass tcs
        must_convert = foldUFM (||) False (intersectUFM_C const cs refs)
                       && (not . isShowClass $ tcs)

        -- We currently admit Haskell 2011-style data and newtype declarations as well as type
        -- constructors representing classes.
        convertable tc 
          = (isDataTyCon tc || isNewTyCon tc) && all isVanillaDataCon (tyConDataCons tc)
            || isClassTyCon tc
            
        -- !!!FIXME: currently we allow 'Show' in vectorised code without actually providing a
        --   vectorised definition (to be able to vectorise 'Num')
        isShowClass [tc] = tyConName tc == showClassName
        isShowClass _    = False

-- Used to group type constructors into mutually dependent groups.
--
classifyTyCons :: UniqFM Bool                     -- ^type constructor conversion status
               -> [TyCon]                         -- ^type constructors that need to be classified
               -> ([TyCon], [TyCon], [TyCon])
classifyTyCons convStatus tcs = classify [] [] [] convStatus (tyConGroups tcs)
  where
    classify conv keep ignored _  [] = (conv, keep, ignored)
    classify conv keep ignored cs ((tcs, ds) : rs)
      | can_convert && must_convert
      = classify (tcs ++ conv) keep ignored (cs `addListToUFM` [(tc, True) | tc <- tcs]) rs
      | can_convert
      = classify conv (tcs ++ keep) ignored (cs `addListToUFM` [(tc, False) | tc <- tcs]) rs
      | otherwise
      = classify conv keep (tcs ++ ignored) cs rs
      where
        refs = ds `delListFromUniqSet` tcs

        can_convert  = (isNullUFM (refs `minusUFM` cs) && all convertable tcs)
                       || isShowClass tcs
        must_convert = foldUFM (||) False (intersectUFM_C const cs refs)
                       && (not . isShowClass $ tcs)

        -- We currently admit Haskell 2011-style data and newtype declarations as well as type
        -- constructors representing classes.
        convertable tc 
          = (isDataTyCon tc || isNewTyCon tc) && all isVanillaDataCon (tyConDataCons tc)
            || isClassTyCon tc
            
        -- !!!FIXME: currently we allow 'Show' in vectorised code without actually providing a
        --   vectorised definition (to be able to vectorise 'Num')
        isShowClass [tc] = tyConName tc == showClassName
        isShowClass _    = False

-- Used to group type constructors into mutually dependent groups.
--
classifyTyCons convStatus tcs = classify [] [] [] convStatus (tyConGroups tcs)
  where
    classify conv keep ignored _  [] = (conv, keep, ignored)
    classify conv keep ignored cs ((tcs, ds) : rs)
      | can_convert && must_convert
      = classify (tcs ++ conv) keep ignored (cs `addListToUFM` [(tc, True) | tc <- tcs]) rs
      | can_convert
      = classify conv (tcs ++ keep) ignored (cs `addListToUFM` [(tc, False) | tc <- tcs]) rs
      | otherwise
      = classify conv keep (tcs ++ ignored) cs rs
      where
        refs = ds `delListFromUniqSet` tcs

        can_convert  = (isNullUFM (refs `minusUFM` cs) && all convertable tcs)
                       || isShowClass tcs
        must_convert = foldUFM (||) False (intersectUFM_C const cs refs)
                       && (not . isShowClass $ tcs)

        -- We currently admit Haskell 2011-style data and newtype declarations as well as type
        -- constructors representing classes.
        convertable tc 
          = (isDataTyCon tc || isNewTyCon tc) && all isVanillaDataCon (tyConDataCons tc)
            || isClassTyCon tc
            
        -- !!!FIXME: currently we allow 'Show' in vectorised code without actually providing a
        --   vectorised definition (to be able to vectorise 'Num')
        isShowClass [tc] = tyConName tc == showClassName
        isShowClass _    = False

-- Used to group type constructors into mutually dependent groups.
--