packages feed

inferno-core-0.1.0.0: src/Inferno/Infer/Error.hs

{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

module Inferno.Infer.Error where

import Data.Functor.Foldable (cata, embed)
import Data.Functor.Foldable.TH (makeBaseFunctor)
import qualified Data.Set as Set
import Inferno.Infer.Env (Namespace)
import Inferno.Infer.Exhaustiveness (Pattern)
import Inferno.Types.Syntax
  ( ExtIdent,
    Ident,
    ModuleName,
    Pat,
    Scoped,
  )
import Inferno.Types.Type
  ( InfernoType,
    Substitutable (..),
    TV,
    TypeClass,
  )
import Inferno.Types.VersionControl (Pinned, VCObjectHash)

type Location a = (a, a)

data TypeError a
  = UnificationFail (Set.Set TypeClass) InfernoType InfernoType (Location a)
  | ExpectedFunction (Set.Set TypeClass) InfernoType InfernoType (Location a)
  | InfiniteType TV InfernoType (Location a)
  | UnboundNameInNamespace (Scoped ModuleName) (Either VCObjectHash Namespace) (Location a)
  | UnboundExtIdent (Scoped ModuleName) ExtIdent (Location a)
  | -- | UnificationMismatch (Set.Set TypeClass) InfernoType InfernoType (Location a)
    -- | Ambiguous [Constraint]
    ImplicitVarTypeOverlap (Set.Set TypeClass) ExtIdent InfernoType InfernoType (Location a)
  | VarMultipleOccurrence Ident (Location a) (Location a)
  | IfConditionMustBeBool (Set.Set TypeClass) InfernoType (Location a)
  | AssertConditionMustBeBool (Set.Set TypeClass) InfernoType (Location a)
  | IfBranchesMustBeEqType (Set.Set TypeClass) InfernoType InfernoType (Location a) (Location a)
  | CaseBranchesMustBeEqType (Set.Set TypeClass) InfernoType InfernoType (Location a) (Location a)
  | PatternUnificationFail InfernoType InfernoType (Pat (Pinned VCObjectHash) a) (Location a)
  | PatternsMustBeEqType (Set.Set TypeClass) InfernoType InfernoType (Pat (Pinned VCObjectHash) a) (Pat (Pinned VCObjectHash) a) (Location a) (Location a)
  | -- | TypeClassUnificationError InfernoType InfernoType TypeClass (Location a)
    TypeClassNotFoundError (Set.Set TypeClass) TypeClass (Location a)
  | TypeClassNoPartialMatch TypeClass (Location a)
  | CouldNotFindTypeclassWitness (Set.Set TypeClass) (Location a)
  | NonExhaustivePatternMatch Pattern (Location a)
  | UselessPattern (Maybe (Pat (Pinned VCObjectHash) a)) (Location a)
  | ModuleNameTaken ModuleName (Location a)
  | ModuleDoesNotExist ModuleName (Location a)
  | NameInModuleDoesNotExist ModuleName Ident (Location a)
  | AmbiguousName ModuleName Namespace (Location a)
  deriving (Show, Eq, Ord, Foldable)

makeBaseFunctor ''TypeError

instance Substitutable (TypeError a) where
  apply s = cata go
    where
      go :: TypeErrorF a (TypeError a) -> TypeError a
      go teF = embed $ fmap (apply s) teF

  ftv _ = Set.empty

getLocFromErr :: TypeError a -> [Location a]
getLocFromErr = go . foldr (:) []
  where
    go = \case
      [] -> []
      (x : y : xs) -> (x, y) : go xs
      _ -> undefined

getLocFromErrs :: [TypeError b] -> [Location b]
getLocFromErrs = concatMap getLocFromErr

getTypeClassFromErr :: TypeError a -> Set.Set TypeClass
getTypeClassFromErr = \case
  UnificationFail tyCls _ _ _ -> tyCls
  ExpectedFunction tyCls _ _ _ -> tyCls
  ImplicitVarTypeOverlap tyCls _ _ _ _ -> tyCls
  IfConditionMustBeBool tyCls _ _ -> tyCls
  AssertConditionMustBeBool tyCls _ _ -> tyCls
  IfBranchesMustBeEqType tyCls _ _ _ _ -> tyCls
  CaseBranchesMustBeEqType tyCls _ _ _ _ -> tyCls
  PatternsMustBeEqType tyCls _ _ _ _ _ _ -> tyCls
  _ -> mempty

getTypeClassFromErrs :: [TypeError a] -> Set.Set TypeClass
getTypeClassFromErrs = foldr Set.union mempty . map getTypeClassFromErr