synthExpr defs gam pol (App s _ e e') = do
    (fTy, gam1, subst1, elaboratedL) <- synthExpr defs gam pol e

    case fTy of
      -- Got a function type for the left-hand side of application
      (FunTy sig tau) -> do
         liftIO $ debugM "FunTy sig" $ pretty sig
         (gam2, subst2, elaboratedR) <- checkExpr defs gam (flipPol pol) False sig e'
         gamNew <- ctxtPlus s gam1 gam2

         subst <- combineSubstitutions s subst1 subst2

         -- Synth subst
         tau    <- substitute subst2 tau

         let elaborated = App s tau elaboratedL elaboratedR
         return (tau, gamNew, subst, elaborated)

      -- Not a function type
      t -> throw LhsOfApplicationNotAFunction{ errLoc = s, errTy = t }

{- Promotion

[G] |- e : t
 ---------------------
[G]*r |- [e] : []_r t

-}
synthExpr defs gam pol (App s _ e e') = do
    (fTy, gam1, subst1, elaboratedL) <- synthExpr defs gam pol e

    case fTy of
      -- Got a function type for the left-hand side of application
      (FunTy sig tau) -> do
         liftIO $ debugM "FunTy sig" $ pretty sig
         (gam2, subst2, elaboratedR) <- checkExpr defs gam (flipPol pol) False sig e'
         gamNew <- ctxtPlus s gam1 gam2

         subst <- combineSubstitutions s subst1 subst2

         -- Synth subst
         tau    <- substitute subst2 tau

         let elaborated = App s tau elaboratedL elaboratedR
         return (tau, gamNew, subst, elaborated)

      -- Not a function type
      t -> throw LhsOfApplicationNotAFunction{ errLoc = s, errTy = t }

{- Promotion

[G] |- e : t
 ---------------------
[G]*r |- [e] : []_r t

-}
synthExpr defs gam pol (App s _ e e') = do
    (fTy, gam1, subst1, elaboratedL) <- synthExpr defs gam pol e

    case fTy of
      -- Got a function type for the left-hand side of application
      (FunTy sig tau) -> do
         liftIO $ debugM "FunTy sig" $ pretty sig
         (gam2, subst2, elaboratedR) <- checkExpr defs gam (flipPol pol) False sig e'
         gamNew <- ctxtPlus s gam1 gam2

         subst <- combineSubstitutions s subst1 subst2

         -- Synth subst
         tau    <- substitute subst2 tau

         let elaborated = App s tau elaboratedL elaboratedR
         return (tau, gamNew, subst, elaborated)

      -- Not a function type
      t -> throw LhsOfApplicationNotAFunction{ errLoc = s, errTy = t }

{- Promotion

[G] |- e : t
 ---------------------
[G]*r |- [e] : []_r t

-}