packages feed

disco-0.1.0.0: src/Disco/Typecheck/Constraints.hs

{-# LANGUAGE DeriveAnyClass    #-}
{-# LANGUAGE OverloadedStrings #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Disco.Typecheck.Constraints
-- Copyright   :  disco team and contributors
-- Maintainer  :  byorgey@gmail.com
--
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Constraints generated by type inference & checking.
--
-----------------------------------------------------------------------------

module Disco.Typecheck.Constraints
  ( Constraint(..)
  , cAnd
  )
  where

import qualified Data.List.NonEmpty               as NE
import           Data.Semigroup
import           GHC.Generics                     (Generic)
import           Unbound.Generics.LocallyNameless hiding (lunbind)

import           Disco.Effects.LFresh

import           Disco.Pretty                     hiding ((<>))
import           Disco.Syntax.Operators           (BFixity (In, InL, InR))
import           Disco.Types
import           Disco.Types.Rules

-- | Constraints are generated as a result of type inference and checking.
--   These constraints are accumulated during the inference and checking phase
--   and are subsequently solved by the constraint solver.
data Constraint where
  CSub   :: Type -> Type -> Constraint
  CEq    :: Type -> Type -> Constraint
  CQual  :: Qualifier -> Type -> Constraint
  CAnd   :: [Constraint] -> Constraint
  CTrue  :: Constraint
  COr    :: [Constraint] -> Constraint
  CAll  :: Bind [Name Type] Constraint -> Constraint

  deriving (Show, Generic, Alpha, Subst Type)

instance Pretty Constraint where
  pretty = \case
    CSub ty1 ty2  -> withPA (PA 4 In) $ lt (pretty ty1) <+> "<:" <+> rt (pretty ty2)
    CEq ty1 ty2   -> withPA (PA 4 In) $ lt (pretty ty1) <+> "=" <+> rt (pretty ty2)
    CQual q ty    -> withPA (PA 10 InL) $ lt (pretty q) <+> rt (pretty ty)
    CAnd [c]      -> pretty c
      -- Use rt for both, since we don't need to print parens for /\ at all
    CAnd (c:cs)   -> withPA (PA 3 InR) $ rt (pretty c) <+> "/\\" <+> rt (pretty (CAnd cs))
    CAnd []       -> "True"
    CTrue         -> "True"
    COr [c]       -> pretty c
    COr (c:cs)    -> withPA (PA 2 InR) $ lt (pretty c) <+> "\\/" <+> rt (pretty (COr cs))
    COr []        -> "False"
    CAll b        -> lunbind b $ \(xs, c) ->
      "∀" <+> intercalate "," (map pretty xs) <> "." <+> pretty c

-- A helper function for creating a single constraint from a list of constraints.
cAnd :: [Constraint] -> Constraint
cAnd cs = case filter nontrivial cs of
  []  -> CTrue
  [c] -> c
  cs' -> CAnd cs'
  where
    nontrivial CTrue = False
    nontrivial _     = True

instance Semigroup Constraint where
  c1 <> c2 = cAnd [c1,c2]
  sconcat  = cAnd . NE.toList
  stimes   = stimesIdempotent

instance Monoid Constraint where
  mempty  = CTrue
  mappend = (<>)
  mconcat = cAnd