@@ -1,99 +1,194 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−module Reporting.Error.Pattern where
3+module Reporting.Error.Pattern
5−import Data.Text (Text)
6−import qualified Data.Text as Text
9+import qualified Data.List as List
8−import qualified Nitpick.Pattern as Pattern
11+import qualified Nitpick.PatternMatches as P
9−import qualified Reporting.Render.Type as RenderType
10−import qualified Reporting.Region as Region
11import qualified Reporting.Report as Report
12import qualified Reporting.Report as Report
12−import qualified Reporting.Helpers as Help
13+import qualified Reporting.Render.Code as Code
14+import qualified Reporting.Helpers as H
13−import Reporting.Helpers ((<>), text)
15+import Reporting.Helpers ((<>))
18− = Incomplete Origin [Pattern.Pattern]
19− | Redundant Region.Region Int
29-- TO REPORT
19-- TO REPORT
32−toReport :: RenderType.Localizer -> Error -> Report.Report
22+toReport :: Code.Source -> P.Error -> Report.Report
33−toReport _localizer err =
23+toReport source err =
34 case err of
24 case err of
35− Incomplete Arg unhandled ->
39− "This pattern does not cover all possible inputs."
40− (text (unhandledError unhandled toCaseMessage))
42− Incomplete LetBound unhandled ->
46− "The pattern used here does not cover all possible values."
47− (text (unhandledError unhandled toCaseMessage))
49− Incomplete Case unhandled ->
53− "This `case` does not have branches for all possibilities."
54− (text (unhandledError unhandled (missingBranchesMessage (length unhandled))))
56− Redundant region index ->
25+ P.Redundant caseRegion patternRegion index ->
58− "REDUNDANT PATTERN"
26+ Report.Report "REDUNDANT PATTERN" patternRegion [] $
59− (Just region)
27+ Report.toCodeSnippet source caseRegion (Just patternRegion)
60− ("The " <> Help.ordinalize index <> " pattern is redundant. Remove it.")
30+ "The " <> H.ordinalize index <> " pattern is redundant:"
61− (text "Any value with this shape will be handled by a previous pattern.")
33+ "Any value with this shape will be handled by a previous\
62−
34+ \ pattern, so it should be removed."
64−unhandledError :: [Pattern.Pattern] -> Text -> Text
36+
65−unhandledError unhandledPatterns relevantMessage =
37+ P.Incomplete region context unhandled ->
66− let
38+ case context of
67− (visiblePatterns, rest) =
39+ P.BadArg ->
68− splitAt 4 unhandledPatterns
40+ Report.Report "UNSAFE PATTERN" region [] $
69−
41+ Report.toCodeSnippet source region Nothing
71− map Pattern.toText visiblePatterns
43+ "This pattern does not cover all possiblities:"
72− ++ if null rest then [] else ["..."]
44+ ,
74− noun =
46+ [ "Other possibilities include:"
75− if length unhandledPatterns == 1 then "pattern" else "patterns"
47+ , unhandledPatternsToDocBlock unhandled
77− "You need to account for the following " <> noun <> ":\n"
49+ "I would have to crash if I saw one of those! So rather than\
78− <> Text.concat (map ("\n " <>) patternList) <> "\n"
50+ \ pattern matching in function arguments, put a `case` in\
79− <> "\n"
51+ \ the function body to account for all possibilities."
80− <> relevantMessage <> "\n"
52+ ]
82− <> "If you are seeing this error for the first time, check out these hints:\n"
54+
56+ Report.Report "UNSAFE PATTERN" region [] $
57+ Report.toCodeSnippet source region Nothing
59+ "This pattern does not cover all possible values:"
62+ [ "Other possibilities include:"
63+ , unhandledPatternsToDocBlock unhandled
65+ "I would have to crash if I saw one of those! You can use\
66+ \ `let` to deconstruct values only if there is ONE possiblity.\
67+ \ Switch to a `case` expression to account for all possibilities."
69+ "Are you calling a function that definitely returns values\
70+ \ with a very specific shape? Try making the return type of\
71+ \ that function more specific!"
76+ Report.Report "MISSING PATTERNS" region [] $
77+ Report.toCodeSnippet source region Nothing
79+ "This `case` does not have branches for all possibilities:"
82+ [ "Missing possibilities include:"
83+ , unhandledPatternsToDocBlock unhandled
85+ "I would have to crash if I saw one of those. Add branches for them!"
87+ "If you want to write the code for each branch later, use `Debug.crash` as a placeholder. Read"
83− <> Help.hintLink "missing-patterns" <> "\n"
88+ "missing-patterns"
84− <> "The recommendations about wildcard patterns and `Debug.crash` are important!"
89+ "for more guidance on this workflow."
87−toCaseMessage :: Text
92+
89− "Switch to a `case` expression to handle all possible patterns."
94+
92−missingBranchesMessage :: Int -> Text
97+
93−missingBranchesMessage numUnhandled =
98+unhandledPatternsToDocBlock :: [P.Pattern] -> H.Doc
94− if numUnhandled == 1 then
99+unhandledPatternsToDocBlock unhandledPatterns =
95− "Add a branch to cover this pattern!"
100+ H.indent 4 $ H.dullyellow $ H.vcat $
96−
101+ map (patternToDoc Unambiguous) unhandledPatterns
111+patternToDoc :: Context -> P.Pattern -> H.Doc
112+patternToDoc context pattern =
113+ case delist pattern [] of
114+ NonList P.Anything ->
117+ NonList (P.Literal literal) ->
120+ H.textToDoc ("'" <> chr <> "'")
123+ H.textToDoc ("\"" <> str <> "\"")
128+ NonList (P.Ctor _ "#0" []) ->
131+ NonList (P.Ctor _ "#2" [a,b]) ->
132+ "( " <> patternToDoc Unambiguous a <>
133+ ", " <> patternToDoc Unambiguous b <>
136+ NonList (P.Ctor _ "#3" [a,b,c]) ->
137+ "( " <> patternToDoc Unambiguous a <>
138+ ", " <> patternToDoc Unambiguous b <>
139+ ", " <> patternToDoc Unambiguous c <>
142+ NonList (P.Ctor _ name args) ->
145+ H.hsep (H.nameToDoc name : map (patternToDoc Arg) args)
147+ if context == Arg && length args > 0 then
148+ "(" <> ctorDoc <> ")"
155+ FiniteList entries ->
156+ let entryDocs = map (patternToDoc Unambiguous) entries in
157+ "[" <> H.hcat (List.intersperse "," entryDocs) <> "]"
159+ Conses conses finalPattern ->
163+ (\hd tl -> patternToDoc Head hd <> " :: " <> tl)
164+ (patternToDoc Unambiguous finalPattern)
167+ if context == Unambiguous then
98− "Add branches to cover each of these patterns!"
170+ "(" <> consDoc <> ")"
174+ = FiniteList [P.Pattern]
175+ | Conses [P.Pattern] P.Pattern
179+delist :: P.Pattern -> [P.Pattern] -> Structure
180+delist pattern revEntries =
183+ FiniteList revEntries
185+ P.Ctor _ "::" [hd,tl] ->
186+ delist tl (hd:revEntries)
194+ Conses (reverse revEntries) pattern