checkExpr defs gam pol True tau (Case s _ guardExpr cases) = do

  -- Synthesise the type of the guardExpr
  (guardTy, guardGam, substG, elaboratedGuard) <- synthExpr defs gam pol guardExpr
  pushGuardContext guardGam

  -- Dependent / GADT pattern matches not allowed in a case
  ixed <- isIndexedType guardTy
  when ixed (throw $ CaseOnIndexedType s guardTy)

  newCaseFrame

  -- Check each of the branches
  branchCtxtsAndSubst <-
    forM cases $ \(pat_i, e_i) -> do

      -- Build the binding context for the branch pattern
      newConjunct
      (patternGam, eVars, subst, elaborated_pat_i, _) <- ctxtFromTypedPattern s guardTy pat_i NotFull
      newConjunct

      -- Checking the case body
      (localGam, subst', elaborated_i) <- checkExpr defs (patternGam <> gam) pol False tau e_i

      -- Check that the use of locally bound variables matches their bound type
      ctxtApprox s (localGam `intersectCtxts` patternGam) patternGam

      -- Conclude the implication
      concludeImplication (getSpan pat_i) eVars

      -- Check linear use in anything Linear
      gamSoFar <- ctxtPlus s guardGam localGam
      case checkLinearity patternGam gamSoFar of
        -- Return the resulting computed context, without any of
        -- the variable bound in the pattern of this branch
        [] -> do
           return (localGam `subtractCtxt` patternGam
                 , subst'
                 , (elaborated_pat_i, elaborated_i))

        -- Anything that was bound in the pattern but not used correctly
        p:ps -> illLinearityMismatch s (p:|ps)

  -- All branches must be possible
  checkGuardsForImpossibility s $ mkId "case"

  -- Pop from stacks related to case
  _ <- popGuardContext
  popCaseFrame

  -- Find the upper-bound of the contexts
  let (branchCtxts, substs, elaboratedCases) = unzip3 branchCtxtsAndSubst
  (branchesGam, tyVars) <- foldM (\(ctxt, vars) ctxt' -> do
    (ctxt'', vars') <- joinCtxts s ctxt ctxt'
    return (ctxt'', vars ++ vars')) (head branchCtxts, []) (tail branchCtxts)

  -- Contract the outgoing context of the guard and the branches (joined)
  g <- ctxtPlus s branchesGam guardGam

  subst <- combineManySubstitutions s (substG : substs)

  -- Exisentially quantify any ty variables generated by joining contexts
  mapM_ (uncurry existential) tyVars

  let elaborated = Case s tau elaboratedGuard elaboratedCases
  return (g, subst, elaborated)

-- All other expressions must be checked using synthesis
checkExpr defs gam pol True tau (Case s _ guardExpr cases) = do

  -- Synthesise the type of the guardExpr
  (guardTy, guardGam, substG, elaboratedGuard) <- synthExpr defs gam pol guardExpr
  pushGuardContext guardGam

  -- Dependent / GADT pattern matches not allowed in a case
  ixed <- isIndexedType guardTy
  when ixed (throw $ CaseOnIndexedType s guardTy)

  newCaseFrame

  -- Check each of the branches
  branchCtxtsAndSubst <-
    forM cases $ \(pat_i, e_i) -> do

      -- Build the binding context for the branch pattern
      newConjunct
      (patternGam, eVars, subst, elaborated_pat_i, _) <- ctxtFromTypedPattern s guardTy pat_i NotFull
      newConjunct

      -- Checking the case body
      (localGam, subst', elaborated_i) <- checkExpr defs (patternGam <> gam) pol False tau e_i

      -- Check that the use of locally bound variables matches their bound type
      ctxtApprox s (localGam `intersectCtxts` patternGam) patternGam

      -- Conclude the implication
      concludeImplication (getSpan pat_i) eVars

      -- Check linear use in anything Linear
      gamSoFar <- ctxtPlus s guardGam localGam
      case checkLinearity patternGam gamSoFar of
        -- Return the resulting computed context, without any of
        -- the variable bound in the pattern of this branch
        [] -> do
           return (localGam `subtractCtxt` patternGam
                 , subst'
                 , (elaborated_pat_i, elaborated_i))

        -- Anything that was bound in the pattern but not used correctly
        p:ps -> illLinearityMismatch s (p:|ps)

  -- All branches must be possible
  checkGuardsForImpossibility s $ mkId "case"

  -- Pop from stacks related to case
  _ <- popGuardContext
  popCaseFrame

  -- Find the upper-bound of the contexts
  let (branchCtxts, substs, elaboratedCases) = unzip3 branchCtxtsAndSubst
  (branchesGam, tyVars) <- foldM (\(ctxt, vars) ctxt' -> do
    (ctxt'', vars') <- joinCtxts s ctxt ctxt'
    return (ctxt'', vars ++ vars')) (head branchCtxts, []) (tail branchCtxts)

  -- Contract the outgoing context of the guard and the branches (joined)
  g <- ctxtPlus s branchesGam guardGam

  subst <- combineManySubstitutions s (substG : substs)

  -- Exisentially quantify any ty variables generated by joining contexts
  mapM_ (uncurry existential) tyVars

  let elaborated = Case s tau elaboratedGuard elaboratedCases
  return (g, subst, elaborated)

-- All other expressions must be checked using synthesis
checkExpr defs gam pol True tau (Case s _ guardExpr cases) = do

  -- Synthesise the type of the guardExpr
  (guardTy, guardGam, substG, elaboratedGuard) <- synthExpr defs gam pol guardExpr
  pushGuardContext guardGam

  -- Dependent / GADT pattern matches not allowed in a case
  ixed <- isIndexedType guardTy
  when ixed (throw $ CaseOnIndexedType s guardTy)

  newCaseFrame

  -- Check each of the branches
  branchCtxtsAndSubst <-
    forM cases $ \(pat_i, e_i) -> do

      -- Build the binding context for the branch pattern
      newConjunct
      (patternGam, eVars, subst, elaborated_pat_i, _) <- ctxtFromTypedPattern s guardTy pat_i NotFull
      newConjunct

      -- Checking the case body
      (localGam, subst', elaborated_i) <- checkExpr defs (patternGam <> gam) pol False tau e_i

      -- Check that the use of locally bound variables matches their bound type
      ctxtApprox s (localGam `intersectCtxts` patternGam) patternGam

      -- Conclude the implication
      concludeImplication (getSpan pat_i) eVars

      -- Check linear use in anything Linear
      gamSoFar <- ctxtPlus s guardGam localGam
      case checkLinearity patternGam gamSoFar of
        -- Return the resulting computed context, without any of
        -- the variable bound in the pattern of this branch
        [] -> do
           return (localGam `subtractCtxt` patternGam
                 , subst'
                 , (elaborated_pat_i, elaborated_i))

        -- Anything that was bound in the pattern but not used correctly
        p:ps -> illLinearityMismatch s (p:|ps)

  -- All branches must be possible
  checkGuardsForImpossibility s $ mkId "case"

  -- Pop from stacks related to case
  _ <- popGuardContext
  popCaseFrame

  -- Find the upper-bound of the contexts
  let (branchCtxts, substs, elaboratedCases) = unzip3 branchCtxtsAndSubst
  (branchesGam, tyVars) <- foldM (\(ctxt, vars) ctxt' -> do
    (ctxt'', vars') <- joinCtxts s ctxt ctxt'
    return (ctxt'', vars ++ vars')) (head branchCtxts, []) (tail branchCtxts)

  -- Contract the outgoing context of the guard and the branches (joined)
  g <- ctxtPlus s branchesGam guardGam

  subst <- combineManySubstitutions s (substG : substs)

  -- Exisentially quantify any ty variables generated by joining contexts
  mapM_ (uncurry existential) tyVars

  let elaborated = Case s tau elaboratedGuard elaboratedCases
  return (g, subst, elaborated)

-- All other expressions must be checked using synthesis