packages feed

egison-5.1.0: hs-src/Language/Egison/Type/TypedDesugar.hs

{- |
Module      : Language.Egison.Type.TypedDesugar
Licence     : MIT

This module implements Phase 7 of the processing flow: TypedDesugar.
It orchestrates type-driven transformations on TIExpr (Typed Internal Expressions)
by calling specialized expansion modules.

Type-Driven Transformations (Phase 7):
  1. Type class dictionary passing (via TypeClassExpand)
     - Instance selection based on types
     - Method call concretization
  2. Type information optimization and embedding
     - Preserve type info for better error messages during evaluation
     - Each node in TIExpr contains its type

Type information is preserved throughout desugaring, enabling:
  - Better runtime error messages with type information
  - Type-based dispatch during evaluation
  - Debugging support with type annotations
-}

module Language.Egison.Type.TypedDesugar
  ( desugarTypedExprT
  , desugarTypedTopExprT
  , desugarTypedTopExprT_TensorMapOnly
  , desugarTypedTopExprT_TypeClassOnly
  ) where

import           Language.Egison.Data       (EvalM)
import           Language.Egison.EvalState  (MonadEval(..))
import           Language.Egison.IExpr      (TIExpr(..), TIExprNode(..), TITopExpr(..), extractNameFromVar, stringToVar)
import           Language.Egison.Type.Env   (lookupEnv)
import           Language.Egison.Type.TensorMapInsertion (insertTensorMaps)
import           Language.Egison.Type.Types (Type(..), TypeScheme(..))
import           Language.Egison.Type.TypeClassExpand (expandTypeClassMethodsT, expandTypeClassMethodsInPattern, addDictionaryParametersT, applyConcreteConstraintDictionaries, applyConcreteConstraintDictionariesInPattern, fixUnboundDictRefs)

-- | Wrap a TIExpr with TIReshape when the type scheme demands a concrete
-- CAS scalar type (Integer, Frac _, Poly _ _, Term _ _, Factor). Skip for
-- polymorphic schemes (any type variables or class constraints), non-CAS
-- types, and TMathValue (which is the most general — reshape is a no-op).
-- This is the post-typecheck elaboration step; placing it after type class
-- expansion preserves inner-method dispatch context.
maybeReshape :: TypeScheme -> TIExpr -> TIExpr
maybeReshape sch@(Forall vars constraints ty) tiexpr
  | not (null vars) || not (null constraints) = tiexpr
  | isReshapeTarget ty = TIExpr sch (TIReshape ty tiexpr)
  | otherwise = tiexpr
  where
    isReshapeTarget :: Type -> Bool
    isReshapeTarget TInt        = True
    isReshapeTarget TFactor     = True
    isReshapeTarget (TFrac _)   = True
    isReshapeTarget (TPoly _ _) = True
    isReshapeTarget (TTerm _ _) = True
    isReshapeTarget _           = False

-- | Desugar a typed expression (TIExpr) with type-driven transformations
-- This function orchestrates the transformation pipeline:
--   1. Insert tensorMap where needed (TensorMapInsertion)
--   2. Expand type class methods (dictionary passing)
--
-- The order matters: tensorMap insertion should happen before type class expansion
-- because after tensorMap insertion, argument types (scalar vs tensor) are determined,
-- which allows type class expansion to use unifyStrict for instance selection.
desugarTypedExprT :: TIExpr -> EvalM TIExpr
desugarTypedExprT tiexpr = do
  -- Step 1: Insert tensorMap where needed
  tiexpr' <- insertTensorMaps tiexpr

  -- Step 2: Expand type class methods (dictionary passing)
  tiexpr'' <- expandTypeClassMethodsT tiexpr'

  return tiexpr''

-- | Desugar a top-level typed expression (TITopExpr)
-- This is the main entry point for Phase 7 transformations.
desugarTypedTopExprT :: TITopExpr -> EvalM (Maybe TITopExpr)
desugarTypedTopExprT topExpr = case topExpr of
  TIDefine scheme var tiexpr -> do
    tiexpr' <- desugarTypedExprT tiexpr
    -- Apply dictionaries to right-hand side if it has concrete type constraints
    tiexpr'' <- applyConcreteConstraintDictionaries tiexpr'
    -- Add dictionary parameters for constrained functions
    tiexpr''' <- addDictionaryParametersT scheme tiexpr''
    -- Repair any dictionary access left unbound (fall back to runtime dispatch)
    classEnv <- getClassEnv
    let tiexprFixed = fixUnboundDictRefs classEnv tiexpr'''
    -- Insert TIReshape from type annotation (post-typecheck elaboration)
    let tiexprFinal = maybeReshape scheme tiexprFixed
    return $ Just (TIDefine scheme var tiexprFinal)

  TITest tiexpr -> do
    tiexpr' <- desugarTypedExprT tiexpr
    classEnv <- getClassEnv
    return $ Just (TITest (fixUnboundDictRefs classEnv tiexpr'))

  TIExecute tiexpr -> do
    tiexpr' <- desugarTypedExprT tiexpr
    classEnv <- getClassEnv
    return $ Just (TIExecute (fixUnboundDictRefs classEnv tiexpr'))
  
  TILoadFile path -> 
    return $ Just (TILoadFile path)
  
  TILoad lib -> 
    return $ Just (TILoad lib)
  
  TIDefineMany bindings -> do
    bindings' <- mapM (\(var, tiexpr) -> do
      tiexpr' <- desugarTypedExprT tiexpr
      -- Add dictionary parameters using the variable's type scheme from TypeEnv
      -- This is important for dictionary definitions where the expression (hash)
      -- may not have constraints, but the variable has constraints in its type scheme
      typeEnv <- getTypeEnv
      let varName = extractNameFromVar var
          scheme = case lookupEnv (stringToVar varName) typeEnv of
                     Just ts -> ts  -- Use type scheme from environment
                     Nothing -> tiScheme tiexpr'  -- Fallback to expression's scheme
      tiexpr'' <- addDictionaryParametersT scheme tiexpr'
      classEnv <- getClassEnv
      return (var, fixUnboundDictRefs classEnv tiexpr'')) bindings
    return $ Just (TIDefineMany bindings')
  
  TIDeclareSymbol names ty ->
    -- Symbol declarations don't need type-driven transformations
    return $ Just (TIDeclareSymbol names ty)
  
  TIPatternFunctionDecl name typeScheme params retType body -> do
    -- Pattern function declarations: apply type class expansion and dictionary application to body
    body' <- expandTypeClassMethodsInPattern body
    body'' <- applyConcreteConstraintDictionariesInPattern body'
    return $ Just (TIPatternFunctionDecl name typeScheme params retType body'')

-- | Desugar a top-level typed expression with TensorMap insertion only
-- This is used for --dump-ti (intermediate dump after TensorMap insertion)
desugarTypedTopExprT_TensorMapOnly :: TITopExpr -> EvalM (Maybe TITopExpr)
desugarTypedTopExprT_TensorMapOnly topExpr = case topExpr of
  TIDefine scheme var tiexpr -> do
    -- Only insert tensorMap (no type class expansion)
    tiexpr' <- insertTensorMaps tiexpr
    return $ Just (TIDefine scheme var tiexpr')

  TITest tiexpr -> do
    tiexpr' <- insertTensorMaps tiexpr
    return $ Just (TITest tiexpr')

  TIExecute tiexpr -> do
    tiexpr' <- insertTensorMaps tiexpr
    return $ Just (TIExecute tiexpr')

  TILoadFile path ->
    return $ Just (TILoadFile path)

  TILoad lib ->
    return $ Just (TILoad lib)

  TIDefineMany bindings -> do
    bindings' <- mapM (\(var, tiexpr) -> do
      tiexpr' <- insertTensorMaps tiexpr
      return (var, tiexpr')) bindings
    return $ Just (TIDefineMany bindings')

  TIDeclareSymbol names ty ->
    return $ Just (TIDeclareSymbol names ty)
  
  TIPatternFunctionDecl name typeScheme params retType body ->
    -- Pattern function declarations: TensorMap insertion only
    return $ Just (TIPatternFunctionDecl name typeScheme params retType body)

-- | Expand type class methods only (assumes TensorMap insertion is already done)
-- This is used internally to perform type class expansion after TensorMap insertion
desugarTypedTopExprT_TypeClassOnly :: TITopExpr -> EvalM (Maybe TITopExpr)
desugarTypedTopExprT_TypeClassOnly topExpr = case topExpr of
  TIDefine scheme var tiexpr -> do
    -- Only expand type class methods (assumes tensorMap is already inserted)
    tiexpr' <- expandTypeClassMethodsT tiexpr
    -- Apply dictionaries to right-hand side if it has concrete type constraints
    tiexpr'' <- applyConcreteConstraintDictionaries tiexpr'
    -- Add dictionary parameters for constrained functions
    tiexpr''' <- addDictionaryParametersT scheme tiexpr''
    -- Repair any dictionary access left unbound (fall back to runtime dispatch)
    classEnv <- getClassEnv
    let tiexprFixed = fixUnboundDictRefs classEnv tiexpr'''
    -- Insert TIReshape from type annotation (post-typecheck elaboration)
    let tiexprFinal = maybeReshape scheme tiexprFixed
    return $ Just (TIDefine scheme var tiexprFinal)

  TITest tiexpr -> do
    tiexpr' <- expandTypeClassMethodsT tiexpr
    tiexpr'' <- applyConcreteConstraintDictionaries tiexpr'
    classEnv <- getClassEnv
    return $ Just (TITest (fixUnboundDictRefs classEnv tiexpr''))

  TIExecute tiexpr -> do
    tiexpr' <- expandTypeClassMethodsT tiexpr
    tiexpr'' <- applyConcreteConstraintDictionaries tiexpr'
    classEnv <- getClassEnv
    return $ Just (TIExecute (fixUnboundDictRefs classEnv tiexpr''))

  TILoadFile path ->
    return $ Just (TILoadFile path)

  TILoad lib ->
    return $ Just (TILoad lib)

  TIDefineMany bindings -> do
    bindings' <- mapM (\(var, tiexpr) -> do
      tiexpr' <- expandTypeClassMethodsT tiexpr
      -- Add dictionary parameters using the variable's type scheme from TypeEnv
      typeEnv <- getTypeEnv
      let varName = extractNameFromVar var
          scheme = case lookupEnv (stringToVar varName) typeEnv of
                     Just ts -> ts
                     Nothing -> tiScheme tiexpr'
      tiexpr'' <- addDictionaryParametersT scheme tiexpr'
      classEnv <- getClassEnv
      return (var, fixUnboundDictRefs classEnv tiexpr'')) bindings
    return $ Just (TIDefineMany bindings')
  
  TIDeclareSymbol names ty ->
    return $ Just (TIDeclareSymbol names ty)
  
  TIPatternFunctionDecl name typeScheme params retType body -> do
    -- Pattern function declarations: expand type class methods and apply dictionaries in body
    body' <- expandTypeClassMethodsInPattern body
    body'' <- applyConcreteConstraintDictionariesInPattern body'
    return $ Just (TIPatternFunctionDecl name typeScheme params retType body'')