Skip to content

Parsing and encoding JSON booleans doesn't roundtrip correctly for code actions #4184

Closed
emacs-lsp/lsp-haskell
#183

Description

@robbert-vdh

Original title: Argument parsing errors when using the 'Add placeholders for ...' code actions in haskell-language-server

Thank you for the bug report

  • I am using the latest version of lsp-mode related packages.
  • I checked FAQ and Troubleshooting sections
  • You may also try reproduce the issue using clean environment using the following command: M-x lsp-start-plain

Bug description

This has been happening for at least a year now. I was silently hoping this would magically get fixed in the meantime (on either the language server's or lsp-mode's side), but I guess that didn't happen. 😄

Also wasn't quite whether to file this under lsp-mode's or lsp-haskell's issue tracker, but since this involves a parsing issue I posted it here.

Using any of the Add placeholders for code actions from Haskell Language Server's class actions plugin results in the following error:

Details
(error "Error while parsing args for classplugin.codeaction in plugin class: expected Bool, but encountered Null, arg = Object (fromList [(\"methodGroup\",Array [Array [String \"show\",String \"show :: Foo -> String\"]]),(\"range\",Object (fromList [(\"end\",Object (fromList [(\"character\",Number 17.0),(\"line\",Number 2.0)])),(\"start\",Object (fromList [(\"character\",Number 9.0),(\"line\",Number 2.0)]))])),(\"verTxtDocId\",Object (fromList [(\"uri\",String \"file:///tmp/foo/Foo.hs\"),(\"version\",Number 44.0)])),(\"withSig\",Null)])")

The issue has previously been reported on hls' issue tracker here: haskell/haskell-language-server#2993

Steps to reproduce

This happens any time you try to execute one of these code actions. The simplest way to reproduce this would be to create a .hs file with the following contents:

data Foo

instance Show Foo where

Then hover over the 'No implicit implementation for' warning at Show Foo and try to execute any of the placeholder code actions.

Expected behavior

I'd expect the placeholders to be inserted.

Which Language Server did you use?

This happens with any HLS version. I recently used 1.8.0.0 up to 2.3.0.0 that all had this issue.

OS

Linux

Error callstack

Backtrace
Debugger entered--Lisp error: (error "Error while parsing args for classplugin.codeactio...")
  error("Error while parsing args for classplugin.codeactio...")
  lsp-request("workspace/executeCommand" (:command "128453:class:classplugin.codeaction" :arguments [#<hash-table equal 4/4 0x1d0616d>]))
  lsp-workspace-command-execute("128453:class:classplugin.codeaction" [#<hash-table equal 4/4 0x1d0616d>])
  lsp-send-execute-command("128453:class:classplugin.codeaction" [#<hash-table equal 4/4 0x1d0616d>])
  lsp--execute-command(#<hash-table equal 3/3 0x1d06117>)
  lsp--execute-code-action(#<hash-table equal 4/4 0x1d060cd>)
  lsp-execute-code-action(#<hash-table equal 4/4 0x1d060cd>)
  funcall-interactively(lsp-execute-code-action #<hash-table equal 4/4 0x1d060cd>)
  command-execute(lsp-execute-code-action)
*lsp-log*
Command "haskell-language-server-wrapper --lsp -l /tmp/hls.log" is present on the path.
Command "haskell-language-server-wrapper --lsp -l /tmp/hls.log" is present on the path.
Found the following clients for /tmp/foo/Foo.hs: (server-id lsp-haskell, priority 0)
The following clients were selected based on priority: (server-id lsp-haskell, priority 0)
Creating watchers for following 1 folders:
  /tmp/foo
Cancelling textDocument/codeAction(7) in hook post-command-hook
*lsp-log: lsp-haskell:128453*
[Trace - 12:21:07 ] Sending request 'textDocument/hover - (6)'.
Params: {
  "textDocument": {
    "uri": "file:///tmp/foo/Foo.hs"
  },
  "position": {
    "line": 2,
    "character": 9
  }
}


[Trace - 12:21:07 ] Sending request 'textDocument/codeAction - (7)'.
Params: {
  "textDocument": {
    "uri": "file:///tmp/foo/Foo.hs"
  },
  "range": {
    "start": {
      "line": 2,
      "character": 9
    },
    "end": {
      "line": 2,
      "character": 9
    }
  },
  "context": {
    "diagnostics": [
      {
        "code": "-Wmissing-methods",
        "message": "• No explicit implementation for\n    either ‘showsPrec’ or ‘show’\n• In the instance declaration for ‘Show Foo’",
        "range": {
          "end": {
            "character": 17,
            "line": 2
          },
          "start": {
            "character": 9,
            "line": 2
          }
        },
        "severity": 2,
        "source": "typecheck"
      }
    ]
  }
}


[Trace - 12:21:07 ] Received response 'textDocument/hover - (6)' in 1ms.
Result: {
  "contents": {
    "kind": "markdown",
    "value": "\n\nShow\n```\n\n*Defined in ‘GHC.Show’* *(base-4.17.2.0)*\n\n"
  },
  "range": {
    "end": {
      "character": 13,
      "line": 2
    },
    "start": {
      "character": 9,
      "line": 2
    }
  }
}


[Trace - 12:21:08 ] Sending notification '$/cancelRequest'.
Params: {
  "id": 7
}


[Trace - 12:21:08 ] Received response 'nil - (7)' in 0ms.
Result: [
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'showsPrec'"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'showsPrec'"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'showsPrec' with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'showsPrec' with signature(s)"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "show",
              "show :: Foo -> String"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'show'"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'show'"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "show",
              "show :: Foo -> String"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'show' with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'show' with signature(s)"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ],
            [
              "show",
              "show :: Foo -> String"
            ],
            [
              "showList",
              "showList :: [Foo] -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for all missing methods"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for all missing methods"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ],
            [
              "show",
              "show :: Foo -> String"
            ],
            [
              "showList",
              "showList :: [Foo] -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for all missing methods with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for all missing methods with signature(s)"
  },
  {
    "diagnostics": [],
    "edit": {
      "changes": {
        "file:///tmp/foo/Foo.hs": [
          {
            "newText": "{-# OPTIONS_GHC -Wno-missing-methods #-}\n",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ]
      }
    },
    "kind": "quickfix",
    "title": "Disable \"missing-methods\" warnings"
  }
]


[Trace - 12:21:09 ] Sending request 'textDocument/codeAction - (8)'.
Params: {
  "textDocument": {
    "uri": "file:///tmp/foo/Foo.hs"
  },
  "range": {
    "start": {
      "line": 2,
      "character": 9
    },
    "end": {
      "line": 2,
      "character": 9
    }
  },
  "context": {
    "diagnostics": [
      {
        "code": "-Wmissing-methods",
        "message": "• No explicit implementation for\n    either ‘showsPrec’ or ‘show’\n• In the instance declaration for ‘Show Foo’",
        "range": {
          "end": {
            "character": 17,
            "line": 2
          },
          "start": {
            "character": 9,
            "line": 2
          }
        },
        "severity": 2,
        "source": "typecheck"
      }
    ]
  }
}


[Trace - 12:21:09 ] Received response 'textDocument/codeAction - (8)' in 7ms.
Result: [
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'showsPrec'"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'showsPrec'"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'showsPrec' with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'showsPrec' with signature(s)"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "show",
              "show :: Foo -> String"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'show'"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'show'"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "show",
              "show :: Foo -> String"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'show' with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'show' with signature(s)"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ],
            [
              "show",
              "show :: Foo -> String"
            ],
            [
              "showList",
              "showList :: [Foo] -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for all missing methods"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for all missing methods"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ],
            [
              "show",
              "show :: Foo -> String"
            ],
            [
              "showList",
              "showList :: [Foo] -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for all missing methods with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for all missing methods with signature(s)"
  },
  {
    "diagnostics": [],
    "edit": {
      "changes": {
        "file:///tmp/foo/Foo.hs": [
          {
            "newText": "{-# OPTIONS_GHC -Wno-missing-methods #-}\n",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ]
      }
    },
    "kind": "quickfix",
    "title": "Disable \"missing-methods\" warnings"
  }
]


[Trace - 12:21:09 ] Sending request 'textDocument/codeAction - (9)'.
Params: {
  "textDocument": {
    "uri": "file:///tmp/foo/Foo.hs"
  },
  "range": {
    "start": {
      "line": 2,
      "character": 9
    },
    "end": {
      "line": 2,
      "character": 9
    }
  },
  "context": {
    "diagnostics": [
      {
        "code": "-Wmissing-methods",
        "message": "• No explicit implementation for\n    either ‘showsPrec’ or ‘show’\n• In the instance declaration for ‘Show Foo’",
        "range": {
          "end": {
            "character": 17,
            "line": 2
          },
          "start": {
            "character": 9,
            "line": 2
          }
        },
        "severity": 2,
        "source": "typecheck"
      }
    ]
  }
}


[Trace - 12:21:09 ] Received response 'textDocument/codeAction - (9)' in 7ms.
Result: [
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'showsPrec'"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'showsPrec'"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'showsPrec' with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'showsPrec' with signature(s)"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "show",
              "show :: Foo -> String"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'show'"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'show'"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "show",
              "show :: Foo -> String"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for 'show' with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for 'show' with signature(s)"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ],
            [
              "show",
              "show :: Foo -> String"
            ],
            [
              "showList",
              "showList :: [Foo] -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": null
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for all missing methods"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for all missing methods"
  },
  {
    "command": {
      "arguments": [
        {
          "methodGroup": [
            [
              "showsPrec",
              "showsPrec :: Int -> Foo -> ShowS"
            ],
            [
              "show",
              "show :: Foo -> String"
            ],
            [
              "showList",
              "showList :: [Foo] -> ShowS"
            ]
          ],
          "range": {
            "end": {
              "character": 17,
              "line": 2
            },
            "start": {
              "character": 9,
              "line": 2
            }
          },
          "verTxtDocId": {
            "uri": "file:///tmp/foo/Foo.hs",
            "version": 0
          },
          "withSig": true
        }
      ],
      "command": "128453:class:classplugin.codeaction",
      "title": "Add placeholders for all missing methods with signature(s)"
    },
    "diagnostics": [],
    "kind": "quickfix",
    "title": "Add placeholders for all missing methods with signature(s)"
  },
  {
    "diagnostics": [],
    "edit": {
      "changes": {
        "file:///tmp/foo/Foo.hs": [
          {
            "newText": "{-# OPTIONS_GHC -Wno-missing-methods #-}\n",
            "range": {
              "end": {
                "character": 0,
                "line": 0
              },
              "start": {
                "character": 0,
                "line": 0
              }
            }
          }
        ]
      }
    },
    "kind": "quickfix",
    "title": "Disable \"missing-methods\" warnings"
  }
]


[Trace - 12:21:11 ] Sending request 'workspace/executeCommand - (10)'.
Params: {
  "command": "128453:class:classplugin.codeaction",
  "arguments": [
    {
      "methodGroup": [
        [
          "show",
          "show :: Foo -> String"
        ]
      ],
      "range": {
        "end": {
          "character": 17,
          "line": 2
        },
        "start": {
          "character": 9,
          "line": 2
        }
      },
      "verTxtDocId": {
        "uri": "file:///tmp/foo/Foo.hs",
        "version": 0
      },
      "withSig": null
    }
  ]
}


[Trace - 12:21:11 ] Received response 'workspace/executeCommand - (10)' in 0ms.
Result: {
  "code": -32602,
  "message": "Error while parsing args for classplugin.codeaction in plugin class: expected Bool, but encountered Null, arg = Object (fromList [(\"methodGroup\",Array [Array [String \"show\",String \"show :: Foo -> String\"]]),(\"range\",Object (fromList [(\"end\",Object (fromList [(\"character\",Number 17.0),(\"line\",Number 2.0)])),(\"start\",Object (fromList [(\"character\",Number 9.0),(\"line\",Number 2.0)]))])),(\"verTxtDocId\",Object (fromList [(\"uri\",String \"file:///tmp/foo/Foo.hs\"),(\"version\",Number 0.0)])),(\"withSig\",Null)])"
}
*lsp-haskell::stderr*
No 'hie.yaml' found. Try to discover the project type!
Run entered for haskell-language-server-wrapper(haskell-language-server-wrapper) Version 2.3.0.0 x86_64 ghc-9.0.2
Current directory: /tmp/foo
Operating system: linux
Arguments: ["--lsp","-l","/tmp/hls.log"]
Cradle directory: /tmp/foo
Cradle type: Default

Tool versions found on the $PATH
cabal:          3.10.1.0
stack:          2.7.5
ghc:            9.4.7


Consulting the cradle to get project GHC version...
2023-10-01T10:21:05.166936Z | Debug | executing command: ghc --numeric-version
Project GHC version: 9.4.7
haskell-language-server exe candidates: ["haskell-language-server-9.4.7","haskell-language-server"]
Launching haskell-language-server exe at:/home/robbert/.ghcup/bin/haskell-language-server-9.4.7
2023-10-01T10:21:05.194101Z | Debug | executing command: ghc -v0 -package-env=- -ignore-dot-ghci -e Control.Monad.join (Control.Monad.fmap System.IO.putStr System.Environment.getExecutablePath)
2023-10-01T10:21:05.273221Z | Debug | executing command: ghc --print-libdir
2023-10-01T10:21:06.284139Z | Info | haskell-language-server version: 2.3.0.0 (GHC: 9.4.7) (PATH: /home/robbert/.ghcup/hls/2.3.0.0/lib/haskell-language-server-2.3.0.0/bin/haskell-language-server-9.4.7)
2023-10-01T10:21:06.284524Z | Info | Directory: /tmp/foo
2023-10-01T10:21:06.284727Z | Info | Starting (haskell-language-server) LSP server...
  GhcideArguments {argsCommand = LSP, argsCwd = Nothing, argsShakeProfiling = Nothing, argsTesting = False, argsExamplePlugin = False, argsLogLevel = Info, argsLogFile = Just "/tmp/hls.log", argsLogStderr = True, argsLogClient = False, argsThreads = 0, argsProjectGhcVersion = False}
  PluginIds: [ pragmas-suggest
             , pragmas-completion
             , retrie
             , ghcide-completions
             , alternateNumberFormat
             , ghcide-code-actions-bindings
             , explicit-fields
             , ghcide-hover-and-symbols
             , ghcide-code-actions-type-signatures
             , floskell
             , fourmolu
             , ghcide-extend-import-action
             , ghcide-code-actions-fill-holes
             , importLens
             , LSPRecorderCallback
             , cabal
             , qualifyImportedNames
             , moduleName
             , splice
             , stylish-haskell
             , changeTypeSignature
             , hlint
             , class
             , ormolu
             , callHierarchy
             , ghcide-type-lenses
             , codeRange
             , cabal-fmt
             , eval
             , rename
             , ghcide-code-actions-imports-exports
             , gadt
             , overloaded-record-dot
             , ghcide-core
             , explicit-fixity
             , pragmas-disable ]
2023-10-01T10:21:06.286618Z | Info | Logging heap statistics every 60.00s
 2023-10-01T10:21:06.302990Z | Info | Starting LSP server...
  If you are seeing this in a terminal, you probably should have run WITHOUT the --lsp option!
  PluginIds: [ pragmas-suggest
             , pragmas-completion
             , retrie
             , ghcide-completions
             , alternateNumberFormat
             , ghcide-code-actions-bindings
             , explicit-fields
             , ghcide-hover-and-symbols
             , ghcide-code-actions-type-signatures
             , floskell
             , fourmolu
             , ghcide-extend-import-action
             , ghcide-code-actions-fill-holes
             , importLens
             , LSPRecorderCallback
             , cabal
             , qualifyImportedNames
             , moduleName
             , splice
             , stylish-haskell
             , changeTypeSignature
             , hlint
             , class
             , ormolu
             , callHierarchy
             , ghcide-type-lenses
             , codeRange
             , cabal-fmt
             , eval
             , rename
             , ghcide-code-actions-imports-exports
             , gadt
             , overloaded-record-dot
             , ghcide-core
             , explicit-fixity
             , pragmas-disable ]
2023-10-01T10:21:06.303284Z | Info | Starting server
2023-10-01T10:21:06.304382Z | Warning | LSP: configuration parse error:
parsing settings failed, expected Object, but encountered Null
when parsing
null
2023-10-01T10:21:06.304803Z | Info | Started LSP server in 0.00s
2023-10-01T10:21:06.337587Z | Info | Registering IDE configuration: IdeConfiguration {workspaceFolders = fromList [NormalizedUri (-6961054525489253453) "file:///tmp/foo"], clientSettings = hashed (Just Null)}
2023-10-01T10:21:06.357826Z | Info | Cradle path: Foo.hs
2023-10-01T10:21:06.357895Z | Warning | No [cradle](https://github.com/mpickering/hie-bios#hie-bios) found for Foo.hs.
Proceeding with [implicit cradle](https://hackage.haskell.org/package/implicit-hie).
You should ignore this message, unless you see a 'Multi Cradle: No prefixes matched' error.
2023-10-01T10:21:06.360657Z | Info | invoking build tool to determine build flags (this may take some time depending on the cache)
2023-10-01T10:21:06.417009Z | Info | Interface files cache directory: /home/robbert/.cache/ghcide/main-1a596a151463f2c53ee4feb14ecd276a1ccebfda-1a596a151463f2c53ee4feb14ecd276a1ccebfda
2023-10-01T10:21:06.417104Z | Info | Making new HscEnv. In-place unit ids: [ main-1a596a151463f2c53ee4feb14ecd276a1ccebfda ]
2023-10-01T10:21:07.931325Z | Info | class: Detected implemented methods for class "Show": []
2023-10-01T10:21:09.633401Z | Info | class: Detected implemented methods for class "Show": []
2023-10-01T10:21:09.763443Z | Info | class: Detected implemented methods for class "Show": []
2023-10-01T10:21:11.322157Z | Warning | class: {
  "code": -32602,
  "message": "Error while parsing args for classplugin.codeaction in plugin class: expected Bool, but encountered Null, arg = Object (fromList [(\"methodGroup\",Array [Array [String \"show\",String \"show :: Foo -> String\"]]),(\"range\",Object (fromList [(\"end\",Object (fromList [(\"character\",Number 17.0),(\"line\",Number 2.0)])),(\"start\",Object (fromList [(\"character\",Number 9.0),(\"line\",Number 2.0)]))])),(\"verTxtDocId\",Object (fromList [(\"uri\",String \"file:///tmp/foo/Foo.hs\"),(\"version\",Number 0.0)])),(\"withSig\",Null)])"
}

Anything else?

No response

Activity

  1. robbert-vdh commented on Oct 13, 2023

    @robbert-vdh
    ContributorAuthor

    So the problem here is that json-parse-buffer translates false to nil, and nil encodes back to JSON as null. Those "withSig": null entries should be "withSig": false.

    It parses this JSON:

    "{\"id\":74,\"jsonrpc\":\"2.0\",\"result\":[{\"command\":{\"arguments\":[{\"methodGroup\":[[\"show\",\"show :: Foo -> String\"]],\"range\":{\"end\":{\"character\":17,\"line\":7},\"start\":{\"character\":9,\"line\":7}},\"verTxtDocId\":{\"uri\":\"file:///home/robbert/Documents/forks/lsp-mode/Foo.hs\",\"version\":2},\"withSig\":false}],\"command\":\"1065989:class:classplugin.codeaction\",\"title\":\"Add placeholders for 'show'\"},\"diagnostics\":[],\"kind\":\"quickfix\",\"title\":\"Add placeholders for 'show'\"},{\"command\":{\"arguments\":[{\"methodGroup\":[[\"show\",\"show :: Foo -> String\"]],\"range\":{\"end\":{\"character\":17,\"line\":7},\"start\":{\"character\":9,\"line\":7}},\"verTxtDocId\":{\"uri\":\"file:///home/robbert/Documents/forks/lsp-mode/Foo.hs\",\"version\":2},\"withSig\":true}],\"command\":\"1065989:class:classplugin.codeaction\",\"title\":\"Add placeholders for 'show' with signature(s)\"},\"diagnostics\":[],\"kind\":\"quickfix\",\"title\":\"Add placeholders for 'show' with signature(s)\"},{\"command\":{\"arguments\":[{\"methodGroup\":[[\"show\",\"show :: Foo -> String\"],[\"showList\",\"showList :: [Foo] -> ShowS\"]],\"range\":{\"end\":{\"character\":17,\"line\":7},\"start\":{\"character\":9,\"line\":7}},\"verTxtDocId\":{\"uri\":\"file:///home/robbert/Documents/forks/lsp-mode/Foo.hs\",\"version\":2},\"withSig\":false}],\"command\":\"1065989:class:classplugin.codeaction\",\"title\":\"Add placeholders for all missing methods\"},\"diagnostics\":[],\"kind\":\"quickfix\",\"title\":\"Add placeholders for all missing methods\"},{\"command\":{\"arguments\":[{\"methodGroup\":[[\"show\",\"show :: Foo -> String\"],[\"showList\",\"showList :: [Foo] -> ShowS\"]],\"range\":{\"end\":{\"character\":17,\"line\":7},\"start\":{\"character\":9,\"line\":7}},\"verTxtDocId\":{\"uri\":\"file:///home/robbert/Documents/forks/lsp-mode/Foo.hs\",\"version\":2},\"withSig\":true}],\"command\":\"1065989:class:classplugin.codeaction\",\"title\":\"Add placeholders for all missing methods with signature(s)\"},\"diagnostics\":[],\"kind\":\"quickfix\",\"title\":\"Add placeholders for all missing methods with signature(s)\"},{\"diagnostics\":[],\"edit\":{\"changes\":{\"file:///home/robbert/Documents/forks/lsp-mode/Foo.hs\":[{\"newText\":\"{-# OPTIONS_GHC -Wno-missing-methods #-}\\n\",\"range\":{\"end\":{\"character\":0,\"line\":0},\"start\":{\"character\":0,\"line\":0}}}]}},\"kind\":\"quickfix\",\"title\":\"Disable \\\"missing-methods\\\" warnings\"}]}"

    To this:

    #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("id" 74 "jsonrpc" "2.0" "result" [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("command" #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("arguments" [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("methodGroup" [["show" "show :: Foo -> String"]] "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 17 "line" 7)) "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 9 "line" 7)))) "verTxtDocId" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("uri" "file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" "version" 2)) "withSig" nil))] "command" "1065989:class:classplugin.codeaction" "title" "Add placeholders for 'show'")) "diagnostics" [] "kind" "quickfix" "title" "Add placeholders for 'show'")) #s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("command" #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("arguments" [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("methodGroup" [["show" "show :: Foo -> String"]] "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 17 "line" 7)) "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 9 "line" 7)))) "verTxtDocId" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("uri" "file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" "version" 2)) "withSig" t))] "command" "1065989:class:classplugin.codeaction" "title" "Add placeholders for 'show' with signature(s)")) "diagnostics" [] "kind" "quickfix" "title" "Add placeholders for 'show' with signature(s)")) #s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("command" #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("arguments" [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("methodGroup" [["show" "show :: Foo -> String"] ["showList" "showList :: [Foo] -> ShowS"]] "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 17 "line" 7)) "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 9 "line" 7)))) "verTxtDocId" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("uri" "file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" "version" 2)) "withSig" nil))] "command" "1065989:class:classplugin.codeaction" "title" "Add placeholders for all missing methods")) "diagnostics" [] "kind" "quickfix" "title" "Add placeholders for all missing methods")) #s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("command" #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("arguments" [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("methodGroup" [["show" "show :: Foo -> String"] ["showList" "showList :: [Foo] -> ShowS"]] "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 17 "line" 7)) "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 9 "line" 7)))) "verTxtDocId" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("uri" "file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" "version" 2)) "withSig" t))] "command" "1065989:class:classplugin.codeaction" "title" "Add placeholders for all missing methods with signature(s)")) "diagnostics" [] "kind" "quickfix" "title" "Add placeholders for all missing methods with signature(s)")) #s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("diagnostics" [] "edit" #s(hash-table size 1 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("changes" #s(hash-table size 1 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" [#s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("newText" "{-# OPTIONS_GHC -Wno-missing-methods #-}
    " "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 0 "line" 0)) "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data ("character" 0 "line" 0))))))])))) "kind" "quickfix" "title" "Disable \"missing-methods\" warnings"))]))

    However, throwing this same input into json-parse-string yields this instead:

    Details
    #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                  ("id" 74 "jsonrpc" "2.0" "result"
                   [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                  ("command" #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                           ("arguments"
                                                            [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                           ("methodGroup"
                                                                            [["show" "show :: Foo -> String"]]
                                                                            "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                  ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                       ("character" 17 "line" 7))
                                                                                                   "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                         ("character" 9 "line" 7))))
                                                                            "verTxtDocId" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                        ("uri" "file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" "version" 2))
                                                                            "withSig" :false))]
                                                            "command" "1065989:class:classplugin.codeaction" "title" "Add placeholders for 'show'"))
                                   "diagnostics"
                                   []
                                   "kind" "quickfix" "title" "Add placeholders for 'show'"))
                      #s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                    ("command" #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                             ("arguments"
                                                              [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                             ("methodGroup"
                                                                              [["show" "show :: Foo -> String"]]
                                                                              "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                    ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                         ("character" 17 "line" 7))
                                                                                                     "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                           ("character" 9 "line" 7))))
                                                                              "verTxtDocId" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                          ("uri" "file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" "version" 2))
                                                                              "withSig" t))]
                                                              "command" "1065989:class:classplugin.codeaction" "title" "Add placeholders for 'show' with signature(s)"))
                                     "diagnostics"
                                     []
                                     "kind" "quickfix" "title" "Add placeholders for 'show' with signature(s)"))
                      #s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                    ("command" #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                             ("arguments"
                                                              [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                             ("methodGroup"
                                                                              [["show" "show :: Foo -> String"]
                                                                               ["showList" "showList :: [Foo] -> ShowS"]]
                                                                              "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                    ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                         ("character" 17 "line" 7))
                                                                                                     "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                           ("character" 9 "line" 7))))
                                                                              "verTxtDocId" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                          ("uri" "file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" "version" 2))
                                                                              "withSig" :false))]
                                                              "command" "1065989:class:classplugin.codeaction" "title" "Add placeholders for all missing methods"))
                                     "diagnostics"
                                     []
                                     "kind" "quickfix" "title" "Add placeholders for all missing methods"))
                      #s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                    ("command" #s(hash-table size 3 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                             ("arguments"
                                                              [#s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                             ("methodGroup"
                                                                              [["show" "show :: Foo -> String"]
                                                                               ["showList" "showList :: [Foo] -> ShowS"]]
                                                                              "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                    ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                         ("character" 17 "line" 7))
                                                                                                     "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                                           ("character" 9 "line" 7))))
                                                                              "verTxtDocId" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                          ("uri" "file:///home/robbert/Documents/forks/lsp-mode/Foo.hs" "version" 2))
                                                                              "withSig" t))]
                                                              "command" "1065989:class:classplugin.codeaction" "title" "Add placeholders for all missing methods with signature(s)"))
                                     "diagnostics"
                                     []
                                     "kind" "quickfix" "title" "Add placeholders for all missing methods with signature(s)"))
                      #s(hash-table size 4 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                    ("diagnostics"
                                     []
                                     "edit" #s(hash-table size 1 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                          ("changes" #s(hash-table size 1 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                   ("file:///home/robbert/Documents/forks/lsp-mode/Foo.hs"
                                                                                    [#s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                                                                   ("newText" "{-# OPTIONS_GHC -Wno-missing-methods #-}
    " "range" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                            ("end" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                 ("character" 0 "line" 0))
                             "start" #s(hash-table size 2 test equal rehash-size 1.5 rehash-threshold 0.8125 data
                                                   ("character" 0 "line" 0))))))]))))
                                     "kind" "quickfix" "title" "Disable \"missing-methods\" warnings"))]))
  2. robbert-vdh commented on Oct 13, 2023

    @robbert-vdh
    ContributorAuthor

    Oh, yes, of course it does this. This is how lsp-mode invokes json-parse-buffer:

    (json-parse-buffer :object-type (if lsp-use-plists
                                        'plist
                                      'hash-table)
     :null-object nil
     :false-object nil)

    It doesn't distinguish between false and null. I'm surprised this doesn't cause more issues.

  3. changed the title [-]Argument parsing errors when using the 'Add placeholders for ...' code actions in haskell-language-server[/-] [+]Parsing and encoding JSON booleans doesn't roundtrip correctly for code actions[/+] on Oct 13, 2023
  4. added a commit that references this issue on Oct 14, 2023
    5ba22db
  5. added a commit that references this issue on Oct 30, 2023
    54b971e
  6. added a commit that references this issue on Jun 9, 2024
    d74c7bd
  7. added a commit that references this issue on Jun 10, 2024
    a1b4c75
  8. michaelpj commented on Jun 11, 2024

    @michaelpj
    Contributor

    Hmm. We already try and be a bit permissive on the HLS side as various clients don't follow the spec. Particularly in terms of using null instead of absent/empty list/false. We accept null to mean "absent", perhaps we could also accept it to mean "false".

  9. robbert-vdh commented on Jun 11, 2024

    @robbert-vdh
    ContributorAuthor

    I think in most cases it wouldn't hurt to treat\ null values as false for the sake of client compatibility! Though we'd probably still need these changes from emacs-lsp/lsp-haskell#183 regardless for compatibility with older versions of HLS. That may sometimes still be necessary when for instance working with a version of GHC no longer supported by the current version of HLS.

  10. dfireBird commented on Dec 28, 2024

    @dfireBird
    Contributor

    This causes an issue now in rust-analyzer where rust-analyzer sends a boolean value inside CompletionItem.data object. See my comments on rust-lang/rust-analyzer#18767.

    Is there a way, so that data within CompletionItem.data is considered as is and sent back? Or at-least something like what lsp-haskell did, but for CompletionItem.data?

    P.S: I searched for issues and found this issue. I can open a new issue with more details, if you need one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions