Skip to content
This repository was archived by the owner on Oct 7, 2020. It is now read-only.

Commit 73bb5c1

Browse files
committed
Improve quality and information density of error message
1 parent 310450e commit 73bb5c1

File tree

3 files changed

+71
-29
lines changed

3 files changed

+71
-29
lines changed

hie-plugin-api/Haskell/Ide/Engine/Cradle.hs

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import Distribution.Helper (Package, projectPackages, pUnits,
1313
unChModuleName, Ex(..), ProjLoc(..),
1414
QueryEnv, mkQueryEnv, runQuery,
1515
Unit, unitInfo, uiComponents,
16-
ChEntrypoint(..))
16+
ChEntrypoint(..), uComponentName)
1717
import Distribution.Helper.Discover (findProjects, getDefaultDistDir)
1818
import Data.Char (toLower)
1919
import Data.Function ((&))
20-
import Data.List (isPrefixOf, isInfixOf, sortOn, find)
20+
import Data.List (isPrefixOf, isInfixOf, sortOn, find, intercalate)
2121
import qualified Data.List.NonEmpty as NonEmpty
2222
import Data.List.NonEmpty (NonEmpty)
2323
import qualified Data.Map as M
@@ -45,10 +45,13 @@ import System.Process (readCreateProcessWithExitCode, shell)
4545
findLocalCradle :: FilePath -> IO Cradle
4646
findLocalCradle fp = do
4747
cradleConf <- BIOS.findCradle fp
48-
case cradleConf of
49-
Just yaml -> BIOS.loadCradle yaml
48+
crdl <- case cradleConf of
49+
Just yaml -> do
50+
debugm $ "Found \"" ++ yaml ++ "\" for \"" ++ fp ++ "\""
51+
BIOS.loadCradle yaml
5052
Nothing -> cabalHelperCradle fp
51-
53+
logm $ "Module \"" ++ fp ++ "\" is loaded by Cradle: " ++ show crdl
54+
return crdl
5255
-- | Check if the given cradle is a stack cradle.
5356
-- This might be used to determine the GHC version to use on the project.
5457
-- If it is a stack-cradle, we have to use `stack path --compiler-exe`
@@ -508,7 +511,7 @@ cabalHelperCradle file = do
508511
debugm $ "Relative Module FilePath: " ++ relativeFp
509512
getComponent env (toList units) relativeFp
510513
>>= \case
511-
Just comp -> do
514+
Right comp -> do
512515
let fs' = getFlags comp
513516
let fs = map (fixImportDirs root) fs'
514517
let targets = getTargets comp relativeFp
@@ -520,11 +523,11 @@ cabalHelperCradle file = do
520523
ComponentOptions { componentOptions = ghcOptions
521524
, componentDependencies = []
522525
}
523-
Nothing -> return
526+
Left err -> return
524527
$ CradleFail
525528
$ CradleError
526529
(ExitFailure 2)
527-
["Could not obtain flags for " ++ fp]
530+
[err]
528531

529532
-- | Get the component the given FilePath most likely belongs to.
530533
-- Lazily ask units whether the given FilePath is part of one of their
@@ -534,25 +537,59 @@ cabalHelperCradle file = do
534537
-- The given FilePath must be relative to the Root of the project
535538
-- the given units belong to.
536539
getComponent
537-
:: QueryEnv pt -> [Unit pt] -> FilePath -> IO (Maybe ChComponentInfo)
538-
getComponent _env [] _fp = return Nothing
539-
getComponent env (unit : units) fp =
540-
try (runQuery (unitInfo unit) env) >>= \case
541-
Left (e :: IOException) -> do
542-
warningm $ "Catching and swallowing an IOException: " ++ show e
543-
warningm
544-
$ "The Exception was thrown in the context of finding"
545-
++ " a component for \""
546-
++ fp
547-
++ "\" in the unit: "
548-
++ show unit
549-
getComponent env units fp
550-
Right ui -> do
551-
let components = M.elems (uiComponents ui)
552-
debugm $ "Unit Info: " ++ show ui
553-
case find (fp `partOfComponent`) components of
554-
Nothing -> getComponent env units fp
555-
comp -> return comp
540+
:: forall pt. QueryEnv pt -> [Unit pt] -> FilePath -> IO (Either String ChComponentInfo)
541+
getComponent env unitCandidates fp = getComponent' [] [] unitCandidates >>=
542+
\case
543+
(tried, failed, Nothing) -> return (Left $ buildErrorMsg tried failed)
544+
(_, _, Just comp) -> return (Right comp)
545+
where
546+
getComponent' :: [Unit pt] -> [Unit pt] -> [Unit pt] -> IO ([Unit pt], [Unit pt], Maybe ChComponentInfo)
547+
getComponent' triedUnits failedUnits [] = return (triedUnits, failedUnits, Nothing)
548+
getComponent' triedUnits failedUnits (unit : units) =
549+
try (runQuery (unitInfo unit) env) >>= \case
550+
Left (e :: IOException) -> do
551+
warningm $ "Catching and swallowing an IOException: " ++ show e
552+
warningm
553+
$ "The Exception was thrown in the context of finding"
554+
++ " a component for \""
555+
++ fp
556+
++ "\" in the unit: "
557+
++ show unit
558+
getComponent' triedUnits (unit:failedUnits) units
559+
Right ui -> do
560+
let components = M.elems (uiComponents ui)
561+
debugm $ "Unit Info: " ++ show ui
562+
case find (fp `partOfComponent`) components of
563+
Nothing -> getComponent' (unit:triedUnits) failedUnits units
564+
comp -> return (triedUnits, failedUnits, comp)
565+
566+
buildErrorMsg :: [Unit pt] -> [Unit pt] -> String
567+
buildErrorMsg triedUnits failedUnits = unlines $
568+
[ "Could not obtain flags for: \"" ++ fp ++ "\"."]
569+
++
570+
[ unlines
571+
[ "The given File was not part of any component."
572+
, "No component exposes this module, we tried the following:"
573+
, intercalate "," (map showUnitInfo triedUnits)
574+
, "If you dont know how to expose a module take a look at: "
575+
, "https://www.haskell.org/cabal/users-guide/developing-packages.html"
576+
]
577+
| not( null triedUnits)
578+
]
579+
++
580+
[ unlines
581+
[ "We could not build all components."
582+
, "If one of these components exposes the module, make sure these compile."
583+
, "The following components failed to compile:"
584+
, intercalate "," (map showUnitInfo failedUnits)
585+
]
586+
| not (null failedUnits)
587+
]
588+
589+
-- TODO: this is terrible
590+
showUnitInfo :: Unit pt -> String
591+
showUnitInfo unit = maybe (show unit) show (uComponentName unit)
592+
556593

557594
-- | Check whether the given FilePath is part of the Component.
558595
-- A FilePath is part of the Component if and only if:

hie-plugin-api/Haskell/Ide/Engine/ModuleCache.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ loadCradle iniDynFlags (NewCradle fp) def action = do
166166
-- just pretend the file doesn't exist.
167167
return $ IdeResultOk def
168168
BIOS.CradleFail err -> do
169-
logm $ "GhcException on cradle initialisation: " ++ show err
169+
logm $ "Fail on cradle initialisation: " ++ show err
170170
return $ IdeResultFail $ IdeError
171171
{ ideCode = OtherError
172172
, ideMessage = Text.pack $ show err

src/Haskell/Ide/Engine/Server.hs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,12 @@ run scheduler _origDir plugins captureFp = flip E.catches handlers $ do
182182

183183
Left (e :: Yaml.ParseException) -> do
184184
logm $ "Failed to parse `hie.yaml`: " ++ show e
185-
sf $ NotShowMessage $ fmServerShowMessageNotification J.MtError ("Couldn't parse hie.yaml: \n" <> T.pack (show e))
185+
sf $ NotShowMessage
186+
$ fmServerShowMessageNotification
187+
J.MtError
188+
( "Couldn't parse hie.yaml: \n"
189+
<> T.pack (Yaml.prettyPrintParseException e)
190+
)
186191

187192
let mcradle = case cradleRes of
188193
Left _ -> Nothing

0 commit comments

Comments
 (0)