checkFunApp :: Type                 -- The function type
            -> [Type]               -- The arg type(s)
            -> MsgDoc              -- Error message
            -> LintM (Maybe Type)   -- Just ty => result type is accurate

checkFunApp fun_ty arg_tys msg
 = do { case mb_msg of
          Just msg -> addErrL msg
          Nothing  -> return ()
      ; return mb_ty }
 where
  (mb_ty, mb_msg) = cfa True fun_ty arg_tys

  cfa :: Bool -> Type -> [Type] -> (Maybe Type          -- Accurate result?
                                   , Maybe MsgDoc)      -- Errors?

  cfa accurate fun_ty []      -- Args have run out; that's fine
      = (if accurate then Just fun_ty else Nothing, Nothing)

  cfa accurate fun_ty arg_tys@(arg_ty':arg_tys')
      | Just (arg_ty, res_ty) <- splitFunTy_maybe fun_ty
      = if accurate && not (arg_ty `stgEqType` arg_ty')
        then (Nothing, Just msg)       -- Arg type mismatch
        else cfa accurate res_ty arg_tys'

      | Just (_, fun_ty') <- splitForAllTy_maybe fun_ty
      = cfa False fun_ty' arg_tys

      | Just (tc,tc_args) <- splitTyConApp_maybe fun_ty
      , isNewTyCon tc
      = if length tc_args < tyConArity tc
        then WARN( True, text "cfa: unsaturated newtype" <+> ppr fun_ty $$ msg )
             (Nothing, Nothing)   -- This is odd, but I've seen it
        else cfa False (newTyConInstRhs tc tc_args) arg_tys

      | Just tc <- tyConAppTyCon_maybe fun_ty
      , not (isTypeFamilyTyCon tc)      -- Definite error
      = (Nothing, Just msg)             -- Too many args

      | otherwise
      = (Nothing, Nothing)
checkFunApp :: Type                 -- The function type
            -> [Type]               -- The arg type(s)
            -> MsgDoc              -- Error message
            -> LintM (Maybe Type)
checkFunApp fun_ty arg_tys msg
 = do { case mb_msg of
          Just msg -> addErrL msg
          Nothing  -> return ()
      ; return mb_ty }
 where
  (mb_ty, mb_msg) = cfa True fun_ty arg_tys

  cfa :: Bool -> Type -> [Type] -> (Maybe Type          -- Accurate result?
                                   , Maybe MsgDoc)      -- Errors?

  cfa accurate fun_ty []      -- Args have run out; that's fine
      = (if accurate then Just fun_ty else Nothing, Nothing)

  cfa accurate fun_ty arg_tys@(arg_ty':arg_tys')
      | Just (arg_ty, res_ty) <- splitFunTy_maybe fun_ty
      = if accurate && not (arg_ty `stgEqType` arg_ty')
        then (Nothing, Just msg)       -- Arg type mismatch
        else cfa accurate res_ty arg_tys'

      | Just (_, fun_ty') <- splitForAllTy_maybe fun_ty
      = cfa False fun_ty' arg_tys

      | Just (tc,tc_args) <- splitTyConApp_maybe fun_ty
      , isNewTyCon tc
      = if length tc_args < tyConArity tc
        then WARN( True, text "cfa: unsaturated newtype" <+> ppr fun_ty $$ msg )
             (Nothing, Nothing)   -- This is odd, but I've seen it
        else cfa False (newTyConInstRhs tc tc_args) arg_tys

      | Just tc <- tyConAppTyCon_maybe fun_ty
      , not (isTypeFamilyTyCon tc)      -- Definite error
      = (Nothing, Just msg)             -- Too many args

      | otherwise
      = (Nothing, Nothing)
checkFunApp fun_ty arg_tys msg
 = do { case mb_msg of
          Just msg -> addErrL msg
          Nothing  -> return ()
      ; return mb_ty }
 where
  (mb_ty, mb_msg) = cfa True fun_ty arg_tys

  cfa :: Bool -> Type -> [Type] -> (Maybe Type          -- Accurate result?
                                   , Maybe MsgDoc)      -- Errors?

  cfa accurate fun_ty []      -- Args have run out; that's fine
      = (if accurate then Just fun_ty else Nothing, Nothing)

  cfa accurate fun_ty arg_tys@(arg_ty':arg_tys')
      | Just (arg_ty, res_ty) <- splitFunTy_maybe fun_ty
      = if accurate && not (arg_ty `stgEqType` arg_ty')
        then (Nothing, Just msg)       -- Arg type mismatch
        else cfa accurate res_ty arg_tys'

      | Just (_, fun_ty') <- splitForAllTy_maybe fun_ty
      = cfa False fun_ty' arg_tys

      | Just (tc,tc_args) <- splitTyConApp_maybe fun_ty
      , isNewTyCon tc
      = if length tc_args < tyConArity tc
        then WARN( True, text "cfa: unsaturated newtype" <+> ppr fun_ty $$ msg )
             (Nothing, Nothing)   -- This is odd, but I've seen it
        else cfa False (newTyConInstRhs tc tc_args) arg_tys

      | Just tc <- tyConAppTyCon_maybe fun_ty
      , not (isTypeFamilyTyCon tc)      -- Definite error
      = (Nothing, Just msg)             -- Too many args

      | otherwise
      = (Nothing, Nothing)