checkExpr defs gam pol _ ty@(Box demand tau) (Val s _ (Promote _ e)) = do
    let vars =
          if hasHole e
            -- If we are promoting soemthing with a hole, then put all free variables in scope
            then map fst gam
            -- Otherwise we need to discharge only things that get used
            else freeVars e

    gamF    <- discToFreshVarsIn s vars gam demand
    (gam', subst, elaboratedE) <- checkExpr defs gamF pol False tau e

    -- Causes a promotion of any typing assumptions that came from variable
    -- inside a guard from an enclosing case that have kind Level
    -- This prevents control-flow attacks and is a special case for Level
    -- (the guard contexts come from a special context in the solver)
    guardGam <- allGuardContexts
    guardGam' <- filterM isLevelKinded guardGam
    gam'' <- multAll s (vars <> map fst guardGam') demand (gam' <> guardGam')

    let elaborated = Val s ty (Promote tau elaboratedE)
    return (gam'', subst, elaborated)
  where
    -- Calculate whether a type assumption is level kinded
    isLevelKinded (_, as) = do
        ty <- inferCoeffectTypeAssumption s as
        return $ case ty of
          Just (TyCon (internalName -> "Level"))
            -> True
          Just (TyApp (TyCon (internalName -> "Interval"))
                      (TyCon (internalName -> "Level")))
            -> True
          _ -> False

-- Check a case expression
checkExpr defs gam pol _ ty@(Box demand tau) (Val s _ (Promote _ e)) = do
    let vars =
          if hasHole e
            -- If we are promoting soemthing with a hole, then put all free variables in scope
            then map fst gam
            -- Otherwise we need to discharge only things that get used
            else freeVars e

    gamF    <- discToFreshVarsIn s vars gam demand
    (gam', subst, elaboratedE) <- checkExpr defs gamF pol False tau e

    -- Causes a promotion of any typing assumptions that came from variable
    -- inside a guard from an enclosing case that have kind Level
    -- This prevents control-flow attacks and is a special case for Level
    -- (the guard contexts come from a special context in the solver)
    guardGam <- allGuardContexts
    guardGam' <- filterM isLevelKinded guardGam
    gam'' <- multAll s (vars <> map fst guardGam') demand (gam' <> guardGam')

    let elaborated = Val s ty (Promote tau elaboratedE)
    return (gam'', subst, elaborated)
  where
    -- Calculate whether a type assumption is level kinded
    isLevelKinded (_, as) = do
        ty <- inferCoeffectTypeAssumption s as
        return $ case ty of
          Just (TyCon (internalName -> "Level"))
            -> True
          Just (TyApp (TyCon (internalName -> "Interval"))
                      (TyCon (internalName -> "Level")))
            -> True
          _ -> False

-- Check a case expression
checkExpr defs gam pol _ ty@(Box demand tau) (Val s _ (Promote _ e)) = do
    let vars =
          if hasHole e
            -- If we are promoting soemthing with a hole, then put all free variables in scope
            then map fst gam
            -- Otherwise we need to discharge only things that get used
            else freeVars e

    gamF    <- discToFreshVarsIn s vars gam demand
    (gam', subst, elaboratedE) <- checkExpr defs gamF pol False tau e

    -- Causes a promotion of any typing assumptions that came from variable
    -- inside a guard from an enclosing case that have kind Level
    -- This prevents control-flow attacks and is a special case for Level
    -- (the guard contexts come from a special context in the solver)
    guardGam <- allGuardContexts
    guardGam' <- filterM isLevelKinded guardGam
    gam'' <- multAll s (vars <> map fst guardGam') demand (gam' <> guardGam')

    let elaborated = Val s ty (Promote tau elaboratedE)
    return (gam'', subst, elaborated)
  where
    -- Calculate whether a type assumption is level kinded
    isLevelKinded (_, as) = do
        ty <- inferCoeffectTypeAssumption s as
        return $ case ty of
          Just (TyCon (internalName -> "Level"))
            -> True
          Just (TyApp (TyCon (internalName -> "Interval"))
                      (TyCon (internalName -> "Level")))
            -> True
          _ -> False

-- Check a case expression