@@ -26,8 +26,8 @@ import Prelude ()
2626import Prelude.Compat
2727
2828import Language.PureScript.Crash
29−import Data.Maybe (catMaybes)
30−import Data.List (nub, groupBy)
29+import Data.Maybe (catMaybes, mapMaybe)
30+import Data.List (nub, groupBy, foldl1')
3131
3232import Control.Monad ((<=<), forM, replicateM, join, unless)
3333import Control.Monad.Error.Class (MonadError(..))
@@ -51,14 +51,42 @@ isLeft (Right _) = False
5151desugarCasesModule :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Module] -> m [Module]
5252desugarCasesModule ms = forM ms $ \(Module ss coms name ds exps) ->
5353 rethrow (addHint (ErrorInModule name)) $
54− Module ss coms name <$> (desugarCases <=< desugarAbs $ ds) <*> pure exps
54+ Module ss coms name <$> (desugarCases <=< desugarAbs <=< validateCases $ ds) <*> pure exps
5555
56−desugarAbs :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]
56+-- |
57+-- Validates that case head and binder lengths match.
58+--
59+validateCases :: forall m. (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]
60+validateCases = flip parU f
61+ where
62+ (f, _, _) = everywhereOnValuesM return validate return
63+
64+ validate :: Expr -> m Expr
65+ validate c@(Case vs alts) = do
66+ let l = length vs
67+ alts' = filter ((l /=) . length . caseAlternativeBinders) alts
68+ unless (null alts') $
69+ throwError . MultipleErrors $ fmap (altError l) (caseAlternativeBinders <$> alts')
70+ return c
71+ validate other = return other
72+
73+ altError :: Int -> [Binder] -> ErrorMessage
74+ altError l bs = withPosition pos $ ErrorMessage [] $ CaseBinderLengthDiffers l bs
75+ where
76+ pos = foldl1' widenSpan (mapMaybe positionedBinder bs)
77+
78+ widenSpan (SourceSpan n start end) (SourceSpan _ start' end') =
79+ SourceSpan n (min start start') (max end end')
80+
81+ positionedBinder (PositionedBinder p _ _) = Just p
82+ positionedBinder _ = Nothing
83+
84+desugarAbs :: forall m. (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]
5785desugarAbs = flip parU f
5886 where
5987 (f, _, _) = everywhereOnValuesM return replace return
6088
61− replace :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => Expr -> m Expr
89+ replace :: Expr -> m Expr
6290 replace (Abs (Right binder) val) = do
6391 ident <- Ident <$> freshName
6492 return $ Abs (Left ident) $ Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] (Right val)]
@@ -67,10 +95,10 @@ desugarAbs = flip parU f
6795-- |
6896-- Replace all top-level binders with case expressions.
6997--
70−desugarCases :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]
98+desugarCases :: forall m. (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]
7199desugarCases = desugarRest <=< fmap join . flip parU toDecls . groupBy inSameGroup
72100 where
73− desugarRest :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [Declaration] -> m [Declaration]
101+ desugarRest :: [Declaration] -> m [Declaration]
74102 desugarRest (TypeInstanceDeclaration name constraints className tys ds : rest) =
75103 (:) <$> (TypeInstanceDeclaration name constraints className tys <$> traverseTypeInstanceBody desugarCases ds) <*> desugarRest rest
76104 desugarRest (ValueDeclaration name nameKind bs result : rest) =