packages feed

th-desugar-1.18: Language/Haskell/TH/Desugar/Subst/Capturing.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Language.Haskell.TH.Desugar.Subst.Capturing
-- Copyright   :  (C) 2024 Ryan Scott
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  Ryan Scott
-- Stability   :  experimental
-- Portability :  non-portable
--
-- Substitutions on 'DType's that do /not/ avoid capture. (For capture-avoiding
-- substitution functions, use "Language.Haskell.TH.Desugar.Subst" instead.)
--
----------------------------------------------------------------------------

module Language.Haskell.TH.Desugar.Subst.Capturing (
  DSubst,

  -- * Non–capture-avoiding substitution
  substTy, substForallTelescope, substTyVarBndrs, substTyVarBndr,
  unionSubsts, unionMaybeSubsts,

  -- * Matching a type template against a type
  IgnoreKinds(..), matchTy
  ) where

import Data.Bifunctor (second)
import qualified Data.List as L
import qualified Data.Map as M

import Language.Haskell.TH.Desugar.AST
import Language.Haskell.TH.Desugar.Subst
  (DSubst, unionSubsts, unionMaybeSubsts, IgnoreKinds(..), matchTy)

-- | Non–capture-avoiding substitution on 'DType's. Unlike the @substTy@
-- function in "Language.Haskell.TH.Desugar.Subst", this 'substTy' function is
-- pure, as it never needs to create fresh names.
substTy :: DSubst -> DType -> DType
substTy subst ty | M.null subst = ty
substTy subst (DForallT tele inner_ty)
  = DForallT tele' inner_ty'
  where
    (subst', tele') = substForallTelescope subst tele
    inner_ty'       = substTy subst' inner_ty
substTy subst (DConstrainedT cxt inner_ty) =
  DConstrainedT (map (substTy subst) cxt) (substTy subst inner_ty)
substTy subst (DAppT ty1 ty2) = substTy subst ty1 `DAppT` substTy subst ty2
substTy subst (DAppKindT ty ki) = substTy subst ty `DAppKindT` substTy subst ki
substTy subst (DSigT ty ki) = substTy subst ty `DSigT` substTy subst ki
substTy subst (DVarT n) =
  case M.lookup n subst of
    Just ki -> ki
    Nothing -> DVarT n
substTy _ ty@(DConT {}) = ty
substTy _ ty@(DArrowT)  = ty
substTy _ ty@(DLitT {}) = ty
substTy _ ty@DWildCardT = ty

-- | Non–capture-avoiding substitution on 'DForallTelescope's. This returns a
-- pair containing the new 'DSubst' as well as a new 'DForallTelescope' value,
-- where the kinds have been substituted.
substForallTelescope :: DSubst -> DForallTelescope -> (DSubst, DForallTelescope)
substForallTelescope s (DForallInvis tvbs) = second DForallInvis $ substTyVarBndrs s tvbs
substForallTelescope s (DForallVis   tvbs) = second DForallVis   $ substTyVarBndrs s tvbs

-- | Non–capture-avoiding substitution on a telescope of 'DTyVarBndr's. This
-- returns a pair containing the new 'DSubst' as well as a new telescope of
-- 'DTyVarBndr's, where the kinds have been substituted.
substTyVarBndrs :: DSubst -> [DTyVarBndr flag] -> (DSubst, [DTyVarBndr flag])
substTyVarBndrs = L.mapAccumL substTyVarBndr

-- | Non–capture-avoiding substitution on a 'DTyVarBndr'. This updates the
-- 'DSubst' to remove the 'DTyVarBndr' name from the domain (as that name is now
-- bound by the 'DTyVarBndr') and applies the substitution to the kind of the
-- 'DTyVarBndr'.
substTyVarBndr :: DSubst -> DTyVarBndr flag -> (DSubst, DTyVarBndr flag)
substTyVarBndr s tvb@(DPlainTV n _) = (M.delete n s, tvb)
substTyVarBndr s (DKindedTV n f k)  = (M.delete n s, DKindedTV n f (substTy s k))