{-# LANGUAGE CPP #-}

module Vectorise.Monad.InstEnv
  ( existsInst
  , lookupInst
  , lookupFamInst
  )
where

import Vectorise.Monad.Global
import Vectorise.Monad.Base
import Vectorise.Env

import DynFlags
import FamInstEnv
import InstEnv
import Class
import Type
import TyCon
import Outputable
import Util


#include "HsVersions.h"


-- Check whether a unique class instance for a given class and type arguments exists.
--
existsInst :: Class -> [Type] -> VM Bool
existsInst cls tys
  = do { instEnv <- readGEnv global_inst_env
       ; return $ either (const False) (const True) (lookupUniqueInstEnv instEnv cls tys)
       }

-- Look up the dfun of a class instance.
--
-- The match must be unique —i.e., match exactly one instance— but the
-- type arguments used for matching may be more specific than those of
-- the class instance declaration.  The found class instances must not have
-- any type variables in the instance context that do not appear in the
-- instances head (i.e., no flexi vars); for details for what this means,
-- see the docs at InstEnv.lookupInstEnv.
--
lookupInst :: Class -> [Type] -> VM (DFunId, [Type])
lookupInst cls tys
  = do { instEnv <- readGEnv global_inst_env
       ; case lookupUniqueInstEnv instEnv cls tys of
           Right (inst, inst_tys) -> return (instanceDFunId inst, inst_tys)
           Left  err              ->
               do dflags <- getDynFlags
                  cantVectorise dflags "Vectorise.Monad.InstEnv.lookupInst:" err
       }

-- Look up a family instance.
--
-- The match must be unique - ie, match exactly one instance - but the
-- type arguments used for matching may be more specific than those of
-- the family instance declaration.
--
-- Return the family instance and its type instance.  For example, if we have
--
--  lookupFamInst 'T' '[Int]' yields (':R42T', 'Int')
--
-- then we have a coercion (ie, type instance of family instance coercion)
--
--  :Co:R42T Int :: T [Int] ~ :R42T Int
--
-- which implies that :R42T was declared as 'data instance T [a]'.
--
lookupFamInst :: TyCon -> [Type] -> VM FamInstMatch
lookupFamInst tycon tys
  = ASSERT( isOpenFamilyTyCon tycon )
    do { instEnv <- readGEnv global_fam_inst_env
       ; case lookupFamInstEnv instEnv tycon tys of
           [match] -> return match
           _other                ->
             do dflags <- getDynFlags
                cantVectorise dflags "Vectorise.Monad.InstEnv.lookupFamInst: not found: "
                           (ppr $ mkTyConApp tycon tys)
       }
