-
-
Notifications
You must be signed in to change notification settings - Fork 367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reduce usages of Prelude/Data.Text.head #2519
Conversation
@@ -34,6 +34,9 @@ buildHypothesis | |||
where | |||
go (occName -> occ, t) | |||
| Just ty <- t | |||
-- TODO what's the intention behind this check? | |||
-- can it be replace with something like `not . isSymOcc`? | |||
-- https://hackage.haskell.org/package/ghc-9.2.1/docs/GHC-Plugins.html#v:isSymOcc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably question for @isovector
My intention is to get rid of this usage of head
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is checking that the bindings in scope were created in source Haskell. GHC makes lots of bindings whose name start with $
or other odd things.
You could replace it with maybe False isAlpha $ headMay $ occNameString occ
@@ -324,7 +325,7 @@ moduleUnit = | |||
Module.moduleUnitId | |||
#endif | |||
|
|||
filterInplaceUnits :: [UnitId] -> [PackageFlag] -> ([UnitId], [PackageFlag]) | |||
filterInplaceUnits :: NE.NonEmpty UnitId -> [PackageFlag] -> ([UnitId], [PackageFlag]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use types unqualified, hope it is the pattern for other data types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto, not sure this one should change.
I got them in windows long time ago, what is your setup? we have some issues about, in nix and windows but lately I don't get them in windows 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most test suites need TASTY_NUM_THREADS=1 to override the default behaviour that runs tests concurrently. The ghcide testsuite sets this implicitly I believe, but others don't.
If that's not enough, just copy the command line from CI
let DocumentPositions{..} = head docs | ||
let DocumentPositions{..} = headNote "Experiments.runBench" docs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that the safe package is best practice anymore. It was created before we had HasCallStack but nowadays head will produce a better error message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and I think if we're going to do this we should replace it with a meaningful error, not just the position where it occurred (although that's somewhat useful).
We also could be more lenient about partial functions in things like tests and benchmarks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't want to have any errors escaping out in this way in ghcide.
But this particular call site is in the benchmark suite which is allowed to error out, and a position is more helpful than any description in that case.
@@ -853,18 +854,18 @@ defineNoDiagnostics op = defineEarlyCutoff $ RuleNoDiagnostics $ \k v -> (Nothin | |||
-- | Request a Rule result if available | |||
use :: IdeRule k v | |||
=> k -> NormalizedFilePath -> Action (Maybe v) | |||
use key file = head <$> uses key [file] | |||
use key file = headNote "Development.IDE.Core.Shake.use" <$> uses key [file] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I commented on the issue, I think you could solve all of these at a stroke by making the underlying uses
functions work on NonEmpty
, which I think would be fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I support the generalization to any Traversable
to use NonEmpty
here
|
||
-- | Request a Rule result, it not available return the last computed result, if any, which may be stale | ||
useWithStale :: IdeRule k v | ||
=> k -> NormalizedFilePath -> Action (Maybe (v, PositionMapping)) | ||
useWithStale key file = head <$> usesWithStale key [file] | ||
useWithStale key file = headNote "Development.IDE.Core.Shake.useWithStale" <$> usesWithStale key [file] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
|
||
-- | Request a Rule result, it not available return the last computed result which may be stale. | ||
-- Errors out if none available. | ||
useWithStale_ :: IdeRule k v | ||
=> k -> NormalizedFilePath -> Action (v, PositionMapping) | ||
useWithStale_ key file = head <$> usesWithStale_ key [file] | ||
useWithStale_ key file = headNote "Development.IDE.Core.Shake.useWithStale_" <$> usesWithStale_ key [file] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
@@ -932,7 +933,7 @@ useNoFile :: IdeRule k v => k -> Action (Maybe v) | |||
useNoFile key = use key emptyFilePath | |||
|
|||
use_ :: IdeRule k v => k -> NormalizedFilePath -> Action v | |||
use_ key file = head <$> uses_ key [file] | |||
use_ key file = headNote "Development.IDE.Core.Shake.use_" <$> uses_ key [file] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
unless (null $ tail lies) $ | ||
addTrailingCommaT (head lies) -- Why we need this? | ||
addTrailingCommaT (headNote "Development.IDE.Plugin.CodeAction.ExactPrint.extendHiding2" lies) -- Why we need this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
@@ -210,7 +211,7 @@ extendImportHandler :: CommandFunction IdeState ExtendImport | |||
extendImportHandler ideState edit@ExtendImport {..} = do | |||
res <- liftIO $ runMaybeT $ extendImportHandler' ideState edit | |||
whenJust res $ \(nfp, wedit@WorkspaceEdit {_changes}) -> do | |||
let (_, List (head -> TextEdit {_range})) = fromJust $ _changes >>= listToMaybe . toList | |||
let (_, List (headNote "Development.IDE.Plugin.Completions.extendImportHandler" -> TextEdit {_range})) = fromJust $ _changes >>= listToMaybe . toList |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should just do nothing if the match fails. It's already inside a whenJust
for the response coming in.
@@ -63,7 +64,9 @@ lookupKind env mod = | |||
fmap (fromRight Nothing) . catchSrcErrors (hsc_dflags env) "span" . lookupName env mod | |||
|
|||
getDocumentationTryGhc :: HscEnv -> Module -> Name -> IO SpanDoc | |||
getDocumentationTryGhc env mod n = head <$> getDocumentationsTryGhc env mod [n] | |||
getDocumentationTryGhc env mod n = | |||
headNote "Development.IDE.Spans.Documentation.getDocumentationTryGhc" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems potentially kind of bad! I think we should do something here. Just return a Maybe
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is similar to uses
in that we are local equational reasoning suffices to prove the absence of errors. You could generalise getDocumentationsTryGhc
to take Traversable
and use a NonEmpty
list in getDocumentationTryGhc
@@ -4886,7 +4886,9 @@ projectCompletionTests = | |||
"import ALocal" | |||
] | |||
compls <- getCompletions doc (Position 1 13) | |||
let item = head $ filter ((== "ALocalModule") . (^. Lens.label)) compls | |||
item <- case find (\c -> c ^. Lens.label == "ALocalModule") compls of | |||
Nothing -> liftIO . assertFailure $ "No completion with label ALocalModule found in : " <> show compls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we enable -fno-ignore-assert ? I don't remember
in fmap wildify . head . drop 5 $ iterated | ||
in fmap wildify . (\xs -> atNote "Wingman.CaseSplit.iterateSplit" xs 5) $ iterated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just use !!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, this one is a bit funny because we know the list is infinite. Hmm.
Nota bene: I addressed:
In #2349 - would merge it in some short order. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good!
In future it would make this sort of thing easier to review if you don't also apply hlint suggestions. It's tempting, but reviewer bandwith is a bottleneck for us. You can always do a trivial "fix hlint suggestions PR" :)
Pepe, I'm interpreting your "Remove" comments as "go back to head
here, because due to the implicit HasCallStack
it is equally informative to headNote
", is that right?
let DocumentPositions{..} = head docs | ||
let DocumentPositions{..} = headNote "Experiments.runBench" docs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and I think if we're going to do this we should replace it with a meaningful error, not just the position where it occurred (although that's somewhat useful).
We also could be more lenient about partial functions in things like tests and benchmarks.
@@ -853,18 +854,18 @@ defineNoDiagnostics op = defineEarlyCutoff $ RuleNoDiagnostics $ \k v -> (Nothin | |||
-- | Request a Rule result if available | |||
use :: IdeRule k v | |||
=> k -> NormalizedFilePath -> Action (Maybe v) | |||
use key file = head <$> uses key [file] | |||
use key file = headNote "Development.IDE.Core.Shake.use" <$> uses key [file] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I commented on the issue, I think you could solve all of these at a stroke by making the underlying uses
functions work on NonEmpty
, which I think would be fine.
@@ -758,7 +761,7 @@ getDependencyInfo fs = Map.fromList <$> mapM do_one fs | |||
-- ID. Therefore we create a fake one and give them all the same unit id. | |||
removeInplacePackages | |||
:: UnitId -- ^ fake uid to use for our internal component | |||
-> [UnitId] | |||
-> NonEmpty UnitId |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps simpler to just convert to a normal list before calling this - I don't think this function needs to require its argument to be non-empty!
@@ -1553,7 +1551,7 @@ rangesForBinding' b (L l (IEThingWith _ thing _ inners labels)) | |||
rangesForBinding' _ _ = [] | |||
|
|||
-- | 'matchRegex' combined with 'unifySpaces' | |||
matchRegexUnifySpaces :: T.Text -> T.Text -> Maybe [T.Text] | |||
matchRegexUnifySpaces :: T.Text -> T.Text -> Maybe (NonEmpty T.Text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get why this is the return type, but it's funny to see Maybe (NonEmpty a)
instead of [a]
!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is funny, but in my experience it's actually the more convenient/"right" choice, whenever you want to do something special for the empty list case.
@@ -324,7 +325,7 @@ moduleUnit = | |||
Module.moduleUnitId | |||
#endif | |||
|
|||
filterInplaceUnits :: [UnitId] -> [PackageFlag] -> ([UnitId], [PackageFlag]) | |||
filterInplaceUnits :: NE.NonEmpty UnitId -> [PackageFlag] -> ([UnitId], [PackageFlag]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto, not sure this one should change.
@@ -63,7 +64,9 @@ lookupKind env mod = | |||
fmap (fromRight Nothing) . catchSrcErrors (hsc_dflags env) "span" . lookupName env mod | |||
|
|||
getDocumentationTryGhc :: HscEnv -> Module -> Name -> IO SpanDoc | |||
getDocumentationTryGhc env mod n = head <$> getDocumentationsTryGhc env mod [n] | |||
getDocumentationTryGhc env mod n = | |||
headNote "Development.IDE.Spans.Documentation.getDocumentationTryGhc" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems potentially kind of bad! I think we should do something here. Just return a Maybe
?
let gibiansky = head (filter (\s -> styleName s == "gibiansky") styles) | ||
let gibiansky = case find (\s -> styleName s == "gibiansky") styles of | ||
Just gibStyle -> gibStyle | ||
Nothing -> error "Ide.Plugin.Floskell.findConfigOrDefault: Style with name 'gibiansky' not found" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just not set the appStyle
if this fails?
in fmap wildify . head . drop 5 $ iterated | ||
in fmap wildify . (\xs -> atNote "Wingman.CaseSplit.iterateSplit" xs 5) $ iterated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, this one is a bit funny because we know the list is infinite. Hmm.
@@ -342,7 +342,7 @@ lookupNameInContext name = do | |||
getDefiningType | |||
:: TacticsM CType | |||
getDefiningType = do | |||
calling_fun_name <- fst . head <$> asks ctxDefiningFuncs | |||
calling_fun_name <- asks (fst . headNote "Wingman.Machinery.getDefiningType" . ctxDefiningFuncs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just below we do something with failure
, can we also use that branch if we fail here?
-- amount of gas we give to auto | ||
= -- Do three passes; this should be good enough for the limited | ||
-- amount of gas we give to auto | ||
(\xs -> atNote "Wingman.Simplify.simplify" xs 3) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another annoying infinite list.
Correct |
Thanks for reviews, I'll address your comments tomorrow. |
I decided to close this PR as it contains too many unrelated changes. |
First batch of fixes to #2514
This is going to be harder than I thought :P
There are more
head
s to come, but opening this just to get initial feedback on the general approach.Also (due to my ocd) I had to fix bunch of hlint warnings which lead to meaningful simplifications.
Vague questions: how are you guys dealing with running tests locally?
I'm getting bunch of
fd:28: hPutBuf: resource vanished (Broken pipe)
when runningcabal test
locally..