haskell / haskell-language-server

Official haskell ide support via language server (LSP). Successor of ghcide & haskell-ide-engine.
Apache License 2.0
2.66k stars 355 forks source link

eval action crashes server when optics are involved #663

Closed xsebek closed 2 years ago

xsebek commented 3 years ago

Your environment

$ haskell-language-server-wrapper --probe-tools
haskell-language-server version: 0.6.0.0 (GHC: 8.10.1) (PATH: /Users/xsebek/.ghcup/bin/haskell-language-server-wrapper-0.6.0) (GIT hash: 372a12e797069dc3ac4fa33dcaabe3b992999d7c)
Tool versions found on the $PATH
cabal:          3.2.0.0
stack:          Not found
ghc:            8.10.2

Which lsp-client do you use: VS Code

Describe your project: Simple cabal init with added dependency on optics and changed MainLib.hs:

module MyLib (someFunc) where

import Optics

-- >>> (\(a,b,c) -> (succ a,b,c)) (1,2,3)
-- (2,2,3)
-- >>> (_1 %~ succ) (1, 2, 3)
--
-- >>> someFunc
--
someFunc :: (Int, Int, Int)
someFunc = (_1 %~ succ) (1, 2, 3)

Contents of hie.yaml:

cradle:
  cabal:
    - path: "./MyLib.hs"
      component: "MyLib"

Steps to reproduce

Run eval action on expression with optic or function which contains them, for example:

-- >>> (\(a,b,c) -> (succ a,b,c)) (1,2,3)
-- (2,2,3)
-- >>> (_1 %~ succ) (1, 2, 3)
--
-- >>> someFunc
--
someFunc :: (Int, Int, Int)
someFunc = (_1 %~ succ) (1, 2, 3)

Expected behaviour

Should evaluate the action as if _1 %~ succ was \(a,b,c) -> (succ a,b,c)

Actual behaviour

The eval crashes the server:

2020-12-10 11:51:15.075881 [ThreadId 268] - finish: runEvalCmd.ghcSession (took 0.00s)
2020-12-10 11:51:15.077079 [ThreadId 270] - finish: runEvalCmd.getModSummary (took 0.00s)
haskell-language-server-wrapper: callProcess: /Users/xsebek/.ghcup/bin/haskell-language-server-8.10.2 "--lsp" (exit -11): failed
[Info  - 11:51:16 AM] Connection to server got closed. Server will restart.
[Error - 11:51:16 AM] Request workspace/executeCommand failed.
Error: Connection got disposed.

The same thing happens with evaluating the lens directly.

Include debug information

Execute in the root of your project the command haskell-language-server --debug . and paste the logs here:

Debug output: ``` $ haskell-language-server-wrapper --debug MyLib.hs Found "$SOME_TMP/hie.yaml" for "$SOME_TMP/a" Module "$SOME_TMP/a" is loaded by Cradle: Cradle {cradleRootDir = "$SOME_TMP", cradleOptsProg = CradleAction: Cabal} Run entered for haskell-language-server-wrapper(haskell-language-server-wrapper) Version 0.6.0.0, Git revision 372a12e797069dc3ac4fa33dcaabe3b992999d7c (dirty) x86_64 ghc-8.10.1 Current directory: $SOME_TMP Operating system: darwin Arguments: ["--debug","MyLib.hs"] Cradle directory: $SOME_TMP Cradle type: Cabal Tool versions found on the $PATH cabal: 3.2.0.0 stack: Not found ghc: 8.10.2 Consulting the cradle to get project GHC version... Project GHC version: 8.10.2 haskell-language-server exe candidates: ["haskell-language-server-8.10.2","haskell-language-server-8.10","haskell-language-server"] Launching haskell-language-server exe at:/Users/xsebek/.ghcup/bin/haskell-language-server-8.10.2 haskell-language-server version: 0.6.0.0 (GHC: 8.10.2) (PATH: /Users/xsebek/.ghcup/bin/haskell-language-server-8.10.2~0.6.0) (GIT hash: 372a12e797069dc3ac4fa33dcaabe3b992999d7c) (haskell-language-server)Ghcide setup tester in $SOME_TMP. Report bugs at https://github.com/haskell/haskell-language-server/issues Tool versions found on the $PATH cabal: 3.2.0.0 stack: Not found ghc: 8.10.2 Step 1/4: Finding files to test in $SOME_TMP Found 1 files Step 2/4: Looking for hie.yaml files that control setup Found 1 cradle Step 3/4: Initializing the IDE Step 4/4: Type checking the files [INFO] Consulting the cradle for "MyLib.hs" Output from setting up the cradle Cradle {cradleRootDir = "$SOME_TMP", cradleOptsProg = CradleAction: Cabal} > Resolving dependencies... > Build profile: -w ghc-8.10.2 -O1 > In order, the following will be built (use -v for more details): > - tmp-0.1.0.0 (lib:MyLib) (configuration changed) > Configuring library 'MyLib' for tmp-0.1.0.0.. > Warning: The 'license-file' field refers to the file 'LICENSE' which does not > exist. > Preprocessing library 'MyLib' for tmp-0.1.0.0.. [INFO] Using interface files cache dir: /Users/xsebek/.cache/ghcide/tmp-0.1.0.0-inplace-MyLib-6663260c9a6116330b14b409a83fcf0dfa27cc29 [INFO] Making new HscEnv[tmp-0.1.0.0-inplace-MyLib] [INFO] finish: User TypeCheck (took 0.17s)Completed (1 file worked, 0 files failed) ```

Paste the logs from the lsp-client, e.g. for VS Code

LSP logs: ``` 2020-12-10 12:12:52.720306 [ThreadId 17] - Opened text document: file://$SOME_TMP/MyLib.hs 2020-12-10 12:12:52.733715 [ThreadId 1956] - finish: CodeAction (took 0.01s) 2020-12-10 12:12:52.737882 [ThreadId 1974] - finish: CodeAction:PackageExports (took 0.00s) 2020-12-10 12:12:52.740907 [ThreadId 1975] - finish: importLens (took 0.00s) 2020-12-10 12:12:52.742561 [ThreadId 1977] - finish: retrie (took 0.00s) 2020-12-10 12:12:52.744837 [ThreadId 1979] - finish: tactic (took 0.00s) 2020-12-10 12:12:52.74625 [ThreadId 1985] - finish: tactic (took 0.00s) 2020-12-10 12:12:52.74646 [ThreadId 1986] - finish: tactic (took 0.00s) 2020-12-10 12:12:52.935338 [ThreadId 1991] - Plugin.makeCodeLens (ideLogger) 2020-12-10 12:12:52.937463 [ThreadId 1992] - finish: codeLens (took 0.00s) 2020-12-10 12:12:52.939431 [ThreadId 1997] - finish: (took 0.00s) 2020-12-10 12:12:52.94095 [ThreadId 1998] - finish: ModuleName.ghcSession (took 0.00s) 2020-12-10 12:12:52.942255 [ThreadId 2000] - finish: ModuleName.GetParsedModule (took 0.00s) 2020-12-10 12:12:58.113564 [ThreadId 2007] - finish: runEvalCmd.ghcSession (took 0.00s) 2020-12-10 12:12:58.115273 [ThreadId 2009] - finish: runEvalCmd.getModSummary (took 0.00s) haskell-language-server-wrapper: callProcess: /Users/xsebek/.ghcup/bin/haskell-language-server-8.10.2 "--lsp" (exit -11): failed [Info - 12:13:00 PM] Connection to server got closed. Server will restart. [Error - 12:13:00 PM] Request workspace/executeCommand failed. Error: Connection got disposed. at Object.dispose (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:90964) at Object.dispose (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:74243) at D.handleConnectionClosed (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:74417) at D.handleConnectionClosed (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:247:9685) at t (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:72568) at n.invoke (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:233221) at i.fire (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:233951) at G (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:82879) at n.invoke (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:233221) at i.fire (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:233951) at u.fireClose (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:252684) at Socket. (/Users/xsebek/.vscode/extensions/haskell.haskell-1.2.0/dist/extension.js:1:253441) at Socket.emit (events.js:228:7) at Pipe. (net.js:664:12) Found "$SOME_TMP/hie.yaml" for "$SOME_TMP/a" Module "$SOME_TMP/a" is loaded by Cradle: Cradle {cradleRootDir = "$SOME_TMP", cradleOptsProg = CradleAction: Cabal} ```
xsebek commented 3 years ago

Not sure if this will be fixed by #438, but is this not supported now, @pepeiborra?

tittoassini commented 3 years ago

Well, that's interesting :-)

438 uses the same evaluation logic as the current implementation (apart from some minor changes) so it also crashes.

xsebek commented 3 years ago

Good to hear that it's not my local problem @tittoassini 🙂 Any idea what aspect of the library causes that? So far, I did not have problems with any other package.

PS: I would have tried to verify it on a Linux server, but I have no idea how to trigger the evaluation from CLI/Vim 😕

googleson78 commented 3 years ago

@xsebek what lsp client are you using for vim? You need to look for a code lens action - that triggers the evaluation

xsebek commented 3 years ago

I have MacVim 8.2 locally with Coc, which works, but I could not find all features such as code lens. (It's not in CocAction at least) Is there an Issue which already explained this?

tittoassini commented 3 years ago

This is a server problem, not a client one.

Unfortunately, the server log doesn't provide any hint.

The module is loaded OK and then during execution, it crashes.

Maybe optics use Template Haskell?

@pepeiborra might know more.

xsebek commented 3 years ago

@tittoassini optics do allow you to create lenses with TH, but I tried this with optics-core (AFAIK TH-Free) with same results.

pepeiborra commented 3 years ago

@tittoassini @googleson78 have you managed to repro? I could not repro on MacOs with 8.8.4 nor 8.10.2

tittoassini commented 3 years ago

strange, I could reproduce it with 8.10.2

xsebek commented 3 years ago

Okay, so not every optic is a problem:

-- >>> lens y (\p i -> p {y = i}) %~ (+1) $ (Point 0 0)
-- Point {x = 0, y = 1}
-- >>> _Right %~ (-1+) $ Right 5 :: Either String Int
-- Left 4

It would be nice if tuple optics worked because they don't seem to use anything prohibited and are very useful. 🥺

If there is any way I can help with this issue, let me know @pepeiborra 😉

tittoassini commented 3 years ago

Hi @xsebek,

the first thing to do would be to write a PR with a few tests so that we can see exactly what is crashing the server and what isn't and what versions/platforms are affected.

xsebek commented 3 years ago

That might be beyond me @tittoassini - current functional testing of eval plugin does not seem to include other packages. I am afraid I do not know the Haskell magic necessary to isolate the problematic part of the optics package. 😢

@pepeiborra I minimized the example and pushed it to GitHub xsebek/test-hls-eval-optics :octocat: Let me know if you can repro

xsebek commented 3 years ago

@tittoassini you were right that extended eval plugin does not change this. 😞 The only difference seems to be that any eval action in documentation of "bad" function now crashes the server:

-- >>> (\(a,b,c) -> (succ a,b,c)) (0,2,3)  -- OK

-- >>> (_1 %~ succ) (0, 2, 3)  -- STILL NOT OK

-- >>> (1,2,3)   -- ALSO NOT OK
-- >>> someFunc  -- STILL NOT OK
someFunc :: (Int, Int, Int)
someFunc = (_1 %~ succ) (0, 2, 3)

Which was expected, I guess. 🤷

If you want to check the updated LSP output with messages it's in the repo (line before crash). 🙂

xsebek commented 2 years ago

Hi, I just remembered this old issue and retried with the current HLS and it now works without issue. :partying_face:

No idea what fixed this or when but I am happy to close this. :slightly_smiling_face: