Ale: Haskell GHC linters aren't aware of Cabal files

Created on 14 Feb 2017  路  16Comments  路  Source: dense-analysis/ale

The Haskell ghc and stack-ghc linters don't load the cabal file information for the project, so things like internal modules, default extensions, etc. don't work. The hlint linter uses the HLint.hs configuration correctly.

It's possible to set default extensions in the Haskell cabal file. This file doesn't appear to be consulted by the Haskell linters, and gives spurious failures.

As an example, you can have

-- Foo.cabal
library:
  default-extensions: LambdaCase

-- Foo.hs
module Foo where

foo :: Maybe a -> Int
foo = \case
    Nothing -> 0
    Just _ -> 1

and the linter will complain that \case is a syntax error, despite being valid syntax.

enhancement

Most helpful comment

Well, hdevtools and ghc-mod are typically somewhat unreliable, and GHC works great in a non-cabal project setting. Good documentation on which of the linters are appropriate for which situations could be helpful.

All 16 comments

I'm not much of a Haskell man myself. Is there a command line argument which can be used to specify the path to .cabal files, or does ghc always just read them from the same directory? If it's the former, then we can pass the location to the command. If it's the latter, then we can copy the .cabal file into the temporary directory the linter runs on. (This happens asynchronously.)

I've been looking into it -- GHC doesn't know anything about cabal files, so cabal/stack probably construct the command line arguments to pass to GHC. I'm trying to see if we can get that info from stack/cabal or if there's a more benign way to get that information.

For a non-external tool, we could scan for cabal files, read the default-extensions field and pass them manually -- ghc -XLambdaCase enables the LambdaCase extension. This would possibly be it's own linter though, just to avoid adding too much complexity.

My recommendation after struggling with this a bit, is to install hdevtools and then use that as a linter (ALE already supports it). hdevtools should be 'cabal-aware'.

Ah, fantastic -- hdevtools support was added three days after I posted this issue. Thanks @rob-b ! :smile:

I wonder if it might make sense to eventually disable the other Haskell linters by default, and recommend hdevtools.

Well, hdevtools and ghc-mod are typically somewhat unreliable, and GHC works great in a non-cabal project setting. Good documentation on which of the linters are appropriate for which situations could be helpful.

Sounds like another situation where there's no solution which will work for everyone, so configuration and documentation are needed.

What if we detect stack.yml and hdevtools binary in $PATH, and use that, but otherwise fall back to ghc and others?

I've not tested but wouldn't setting your linters to ['hdevtools', 'ghc'] have the same effect? It looks like ale does check to see if a given linter is executable so as long ale just tries the next linter when it can't find a linter on PATH this should be the default behaviour. Also bear in mind that hdevtools isn't tied to stack so no need to check for stack.yml

Well, my idea is that if it's a Cabal project (not just Stack, which also uses Cabal), ALE should deal with that for us. The default should be to have hdevtools before ghc in the list of linters, but I don't think that is the default.

How should this be discovered, though? If I don't have hdevtools installed, it'll just fall back to GHC without telling me, and I might never realise that I even can get rid of the superfluous linter errors.

Noticed that this thread is fairly recently active so I thought I'd point out that I just opened #742, which adds a stack build linter. It's a GHC-based linter (not ghc-mod or hdevtools) which is aware of cabal project dependencies if you're using stack.

Doesn't quite fit the "just cabal" discussion that was originally started here, but might still be of interest.

hdevtools and ghc-mod are very unreliable and are not well-maintained. They don't work with recent ghc or cabal versions (ghc-mod doesn't even work with ghc-8.2 right now).

I vote for reopening this issue and further investigation.

I have a plugin intero-neovim that has a Neomake maker. It is possible that someone could provide an ale backend as well.

I have a plugin intero-neovim that has a Neomake maker. It is possible that someone could provide an ale backend as well.

That would be so amazing! I've wanted to look into that for some time now. @w0rp is is possible for ale linters to be defined in other plugins / for an ale linter to call a function defined in another plugin instead of an external process? Or is that something we shouldn't want to do in the first place?

intero is a long running process, rather than one you start separately every time you want to line. intero-neovim contains a bunch of logic for communicating with that process and it would be a shame to have to duplicate in ale, then maintain in two places.

intero requires stack. This issue was about the ghc linter which is the simplest possible one. I think there should be a separate issue for intero support.

ALE linters can work in one of two ways. Either a command can be run, and the output can be taken from that, or ALE can talk to a Language Server Protocol server to get some information from that. If either is possible for intero, then ALE can parse problems from it. If not, then it can't.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sodiumjoe picture sodiumjoe  路  4Comments

catbaron0 picture catbaron0  路  3Comments

amerov picture amerov  路  4Comments

janhellmich picture janhellmich  路  3Comments

trevordmiller picture trevordmiller  路  4Comments