Skip to content
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

Uninterpreted extension with ppx rewriter in the same project #696

Closed
copy opened this issue May 8, 2022 · 9 comments · Fixed by ocaml/opam-repository#21617
Closed

Uninterpreted extension with ppx rewriter in the same project #696

copy opened this issue May 8, 2022 · 9 comments · Fixed by ocaml/opam-repository#21617
Milestone

Comments

@copy
Copy link

copy commented May 8, 2022

Consider this simplified executable and its ppx rewriter:

(* test.ml *)
let%test _ = assert true
(* ppx.ml *)
open Ppxlib
open Ast_pattern

let pat = pstr ((pstr_value nonrecursive ((value_binding ~pat:ppat_any ~expr:__) ^:: nil)) ^:: nil)

let test =
  let expand ~loc ~path:_ e =
    let loc = { loc with loc_ghost = true } in
    match Sys.getenv_opt "RELEASE" with
    | Some _ -> Attribute.explicitly_drop#expression e; [%str ]
    | None -> [%str let () = if Sys.getenv_opt "DO_TEST" <> None then [%e e]]
  in
  Extension.declare_inline "ppx.test"
    Extension.Context.structure_item
    pat
    expand

let () = Driver.register_transformation "ppx" ~extensions:[test]
(executable
 (name test)
 (modules test)
 (preprocess
  (pps ppx)))

(library
 (name ppx)
 (modules ppx)
 (kind (ppx_rewriter))
 (preprocess
  (pps ppxlib.metaquot))
 (libraries ppxlib))

After running dune build test.exe once, and making trivial changes to either ppx.ml or test.ml, ocaml-lsp reports Uninterpreted extension errors in either of the files. The errors are spurious and sometimes go away after making another change. The symptoms are a bit like if ocaml-lsp was running the incorrect preprocessor (e.g. ppxlib.metaquot on test.ml or ppx.exe on ppx.ml).

Here are two logs from nvim (the first one with a spurious error in ppx.ml and the second with an error in test.ml):

[START][2022-05-08 18:42:46] LSP logging initiated
[INFO][2022-05-08 18:42:47] .../vim/lsp/rpc.lua:261	"Starting RPC client"	{  args = {},  cmd = "ocamllsp",  extra = {    cwd = "/tmp/1",    env = {      OCAMLLSP_DEBUG = "1"    }  }}
[DEBUG][2022-05-08 18:42:47] .../vim/lsp/rpc.lua:347	"rpc.send"	{  id = 1,  jsonrpc = "2.0",  method = "initialize",  params = {    capabilities = {      callHierarchy = {        dynamicRegistration = false      },      textDocument = {        codeAction = {          codeActionLiteralSupport = {            codeActionKind = {              valueSet = { "", "Empty", "QuickFix", "Refactor", "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source", "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" }            }          },          dataSupport = true,          dynamicRegistration = false,          resolveSupport = {            properties = { "edit" }          }        },        completion = {          completionItem = {            commitCharactersSupport = false,            deprecatedSupport = false,            documentationFormat = { "markdown", "plaintext" },            preselectSupport = false,            snippetSupport = false          },          completionItemKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }          },          contextSupport = false,          dynamicRegistration = false        },        declaration = {          linkSupport = true        },        definition = {          linkSupport = true        },        documentHighlight = {          dynamicRegistration = false        },        documentSymbol = {          dynamicRegistration = false,          hierarchicalDocumentSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        hover = {          contentFormat = { "markdown", "plaintext" },          dynamicRegistration = false        },        implementation = {          linkSupport = true        },        publishDiagnostics = {          relatedInformation = true,          tagSupport = {            valueSet = { 1, 2 }          }        },        references = {          dynamicRegistration = false        },        rename = {          dynamicRegistration = false,          prepareSupport = true        },        signatureHelp = {          dynamicRegistration = false,          signatureInformation = {            activeParameterSupport = true,            documentationFormat = { "markdown", "plaintext" },            parameterInformation = {              labelOffsetSupport = true            }          }        },        synchronization = {          didSave = true,          dynamicRegistration = false,          willSave = false,          willSaveWaitUntil = false        },        typeDefinition = {          linkSupport = true        }      },      window = {        showDocument = {          support = false        },        showMessage = {          messageActionItem = {            additionalPropertiesSupport = false          }        },        workDoneProgress = true      },      workspace = {        applyEdit = true,        configuration = true,        symbol = {          dynamicRegistration = false,          hierarchicalWorkspaceSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        workspaceEdit = {          resourceOperations = { "rename", "create", "delete" }        },        workspaceFolders = true      }    },    clientInfo = {      name = "Neovim",      version = "0.7.0"    },    initializationOptions = vim.empty_dict(),    processId = 63252,    rootPath = "/tmp/1",    rootUri = "file:///tmp/1",    trace = "off",    workspaceFolders = { {        name = "/tmp/1",        uri = "file:///tmp/1"      } }  }}
[DEBUG][2022-05-08 18:42:47] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 1,  jsonrpc = "2.0",  result = {    capabilities = {      codeActionProvider = {        codeActionKinds = { "quickfix", "construct", "destruct", "inferred_intf", "put module name in identifiers", "remove module name from identifiers", "type-annotate" }      },      codeLensProvider = {        resolveProvider = false      },      completionProvider = {        resolveProvider = true,        triggerCharacters = { ".", "#" }      },      declarationProvider = true,      definitionProvider = true,      documentFormattingProvider = true,      documentHighlightProvider = true,      documentSymbolProvider = true,      executeCommandProvider = {        commands = { "dune/promote" }      },      experimental = {        ocamllsp = {          diagnostic_promotions = true,          handleInferIntf = true,          handleSwitchImplIntf = true,          handleTypedHoles = true,          handleWrappingAstNode = true,          interfaceSpecificLangId = true        }      },      foldingRangeProvider = true,      hoverProvider = true,      referencesProvider = true,      renameProvider = {        prepareProvider = true      },      selectionRangeProvider = true,      signatureHelpProvider = {        triggerCharacters = { " ", "~", "?", ":", "(" }      },      textDocumentSync = {        change = 2,        openClose = true,        save = true,        willSave = false,        willSaveWaitUntil = false      },      typeDefinitionProvider = true,      workspace = {        workspaceFolders = {          changeNotifications = true,          supported = true        }      },      workspaceSymbolProvider = true    },    serverInfo = {      name = "ocamllsp",      version = "1.11.4"    }  }}
[DEBUG][2022-05-08 18:42:47] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "initialized",  params = vim.empty_dict()}
[DEBUG][2022-05-08 18:42:47] .../lua/vim/lsp.lua:982	"LSP[ocamllsp]"	"server_capabilities"	{  codeActionProvider = {    codeActionKinds = { "quickfix", "construct", "destruct", "inferred_intf", "put module name in identifiers", "remove module name from identifiers", "type-annotate" }  },  codeLensProvider = {    resolveProvider = false  },  completionProvider = {    resolveProvider = true,    triggerCharacters = { ".", "#" }  },  declarationProvider = true,  definitionProvider = true,  documentFormattingProvider = true,  documentHighlightProvider = true,  documentSymbolProvider = true,  executeCommandProvider = {    commands = { "dune/promote" }  },  experimental = {    ocamllsp = {      diagnostic_promotions = true,      handleInferIntf = true,      handleSwitchImplIntf = true,      handleTypedHoles = true,      handleWrappingAstNode = true,      interfaceSpecificLangId = true    }  },  foldingRangeProvider = true,  hoverProvider = true,  referencesProvider = true,  renameProvider = {    prepareProvider = true  },  selectionRangeProvider = true,  signatureHelpProvider = {    triggerCharacters = { " ", "~", "?", ":", "(" }  },  textDocumentSync = {    change = 2,    openClose = true,    save = true,    willSave = false,    willSaveWaitUntil = false  },  typeDefinitionProvider = true,  workspace = {    workspaceFolders = {      changeNotifications = true,      supported = true    }  },  workspaceSymbolProvider = true}
[INFO][2022-05-08 18:42:47] .../lua/vim/lsp.lua:983	"LSP[ocamllsp]"	"initialized"	{  resolved_capabilities = {    call_hierarchy = false,    code_action = {      codeActionKinds = { "quickfix", "construct", "destruct", "inferred_intf", "put module name in identifiers", "remove module name from identifiers", "type-annotate" }    },    code_lens = true,    code_lens_resolve = false,    completion = true,    declaration = true,    document_formatting = true,    document_highlight = true,    document_range_formatting = false,    document_symbol = true,    execute_command = true,    find_references = true,    goto_definition = true,    hover = true,    implementation = false,    rename = true,    signature_help = true,    signature_help_trigger_characters = { " ", "~", "?", ":", "(" },    text_document_did_change = 2,    text_document_open_close = true,    text_document_save = true,    text_document_save_include_text = false,    text_document_will_save = false,    text_document_will_save_wait_until = false,    type_definition = true,    workspace_folder_properties = {      changeNotifications = true,      supported = true    },    workspace_symbol = true  }}
[DEBUG][2022-05-08 18:42:47] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didOpen",  params = {    textDocument = {      languageId = "ocaml",      text = "let%test _ = assert true\n",      uri = "file:///tmp/1/test.ml",      version = 0    }  }}
[DEBUG][2022-05-08 18:42:47] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = {},    uri = "file:///tmp/1/test.ml"  }}
[DEBUG][2022-05-08 18:42:51] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didOpen",  params = {    textDocument = {      languageId = "ocaml",      text = 'open Ppxlib\nopen Ast_pattern\n\nlet pat = pstr ((pstr_value nonrecursive ((value_binding ~pat:ppat_any ~expr:__) ^:: nil)) ^:: nil)\n\nlet test =\n  let expand ~loc ~path:_ e =\n    let loc = { loc with loc_ghost = true } in\n    match Sys.getenv_opt "RELEASE" with\n    | Some _ -> Attribute.explicitly_drop#expression e; [%str ]\n    | None -> [%str let () = if Sys.getenv_opt "DO_TEST" <> None then [%e e]]\n  in\n  Extension.declare_inline "ppx.test"\n    Extension.Context.structure_item\n    pat\n    expand\n\nlet () = Driver.register_transformation "ppx" ~extensions:[test]\n',      uri = "file:///tmp/1/ppx.ml",      version = 0    }  }}
[DEBUG][2022-05-08 18:42:52] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = { {        message = "Error (warning 26): unused variable loc.",        range = {          end = {            character = 11,            line = 7          },          start = {            character = 8,            line = 7          }        },        severity = 2,        source = "ocamllsp"      }, {        message = "Uninterpreted extension 'str'.",        range = {          end = {            character = 61,            line = 9          },          start = {            character = 58,            line = 9          }        },        severity = 1,        source = "ocamllsp"      }, {        message = "Uninterpreted extension 'str'.",        range = {          end = {            character = 19,            line = 10          },          start = {            character = 16,            line = 10          }        },        severity = 1,        source = "ocamllsp"      } },    uri = "file:///tmp/1/ppx.ml"  }}
[START][2022-05-08 18:43:57] LSP logging initiated
[INFO][2022-05-08 18:43:57] .../vim/lsp/rpc.lua:261	"Starting RPC client"	{  args = {},  cmd = "ocamllsp",  extra = {    cwd = "/tmp/1",    env = {      OCAMLLSP_DEBUG = "1"    }  }}
[DEBUG][2022-05-08 18:43:57] .../vim/lsp/rpc.lua:347	"rpc.send"	{  id = 1,  jsonrpc = "2.0",  method = "initialize",  params = {    capabilities = {      callHierarchy = {        dynamicRegistration = false      },      textDocument = {        codeAction = {          codeActionLiteralSupport = {            codeActionKind = {              valueSet = { "", "Empty", "QuickFix", "Refactor", "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source", "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" }            }          },          dataSupport = true,          dynamicRegistration = false,          resolveSupport = {            properties = { "edit" }          }        },        completion = {          completionItem = {            commitCharactersSupport = false,            deprecatedSupport = false,            documentationFormat = { "markdown", "plaintext" },            preselectSupport = false,            snippetSupport = false          },          completionItemKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }          },          contextSupport = false,          dynamicRegistration = false        },        declaration = {          linkSupport = true        },        definition = {          linkSupport = true        },        documentHighlight = {          dynamicRegistration = false        },        documentSymbol = {          dynamicRegistration = false,          hierarchicalDocumentSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        hover = {          contentFormat = { "markdown", "plaintext" },          dynamicRegistration = false        },        implementation = {          linkSupport = true        },        publishDiagnostics = {          relatedInformation = true,          tagSupport = {            valueSet = { 1, 2 }          }        },        references = {          dynamicRegistration = false        },        rename = {          dynamicRegistration = false,          prepareSupport = true        },        signatureHelp = {          dynamicRegistration = false,          signatureInformation = {            activeParameterSupport = true,            documentationFormat = { "markdown", "plaintext" },            parameterInformation = {              labelOffsetSupport = true            }          }        },        synchronization = {          didSave = true,          dynamicRegistration = false,          willSave = false,          willSaveWaitUntil = false        },        typeDefinition = {          linkSupport = true        }      },      window = {        showDocument = {          support = false        },        showMessage = {          messageActionItem = {            additionalPropertiesSupport = false          }        },        workDoneProgress = true      },      workspace = {        applyEdit = true,        configuration = true,        symbol = {          dynamicRegistration = false,          hierarchicalWorkspaceSymbolSupport = true,          symbolKind = {            valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }          }        },        workspaceEdit = {          resourceOperations = { "rename", "create", "delete" }        },        workspaceFolders = true      }    },    clientInfo = {      name = "Neovim",      version = "0.7.0"    },    initializationOptions = vim.empty_dict(),    processId = 63494,    rootPath = "/tmp/1",    rootUri = "file:///tmp/1",    trace = "off",    workspaceFolders = { {        name = "/tmp/1",        uri = "file:///tmp/1"      } }  }}
[DEBUG][2022-05-08 18:43:57] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 1,  jsonrpc = "2.0",  result = {    capabilities = {      codeActionProvider = {        codeActionKinds = { "quickfix", "construct", "destruct", "inferred_intf", "put module name in identifiers", "remove module name from identifiers", "type-annotate" }      },      codeLensProvider = {        resolveProvider = false      },      completionProvider = {        resolveProvider = true,        triggerCharacters = { ".", "#" }      },      declarationProvider = true,      definitionProvider = true,      documentFormattingProvider = true,      documentHighlightProvider = true,      documentSymbolProvider = true,      executeCommandProvider = {        commands = { "dune/promote" }      },      experimental = {        ocamllsp = {          diagnostic_promotions = true,          handleInferIntf = true,          handleSwitchImplIntf = true,          handleTypedHoles = true,          handleWrappingAstNode = true,          interfaceSpecificLangId = true        }      },      foldingRangeProvider = true,      hoverProvider = true,      referencesProvider = true,      renameProvider = {        prepareProvider = true      },      selectionRangeProvider = true,      signatureHelpProvider = {        triggerCharacters = { " ", "~", "?", ":", "(" }      },      textDocumentSync = {        change = 2,        openClose = true,        save = true,        willSave = false,        willSaveWaitUntil = false      },      typeDefinitionProvider = true,      workspace = {        workspaceFolders = {          changeNotifications = true,          supported = true        }      },      workspaceSymbolProvider = true    },    serverInfo = {      name = "ocamllsp",      version = "1.11.4"    }  }}
[DEBUG][2022-05-08 18:43:57] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "initialized",  params = vim.empty_dict()}
[DEBUG][2022-05-08 18:43:57] .../lua/vim/lsp.lua:982	"LSP[ocamllsp]"	"server_capabilities"	{  codeActionProvider = {    codeActionKinds = { "quickfix", "construct", "destruct", "inferred_intf", "put module name in identifiers", "remove module name from identifiers", "type-annotate" }  },  codeLensProvider = {    resolveProvider = false  },  completionProvider = {    resolveProvider = true,    triggerCharacters = { ".", "#" }  },  declarationProvider = true,  definitionProvider = true,  documentFormattingProvider = true,  documentHighlightProvider = true,  documentSymbolProvider = true,  executeCommandProvider = {    commands = { "dune/promote" }  },  experimental = {    ocamllsp = {      diagnostic_promotions = true,      handleInferIntf = true,      handleSwitchImplIntf = true,      handleTypedHoles = true,      handleWrappingAstNode = true,      interfaceSpecificLangId = true    }  },  foldingRangeProvider = true,  hoverProvider = true,  referencesProvider = true,  renameProvider = {    prepareProvider = true  },  selectionRangeProvider = true,  signatureHelpProvider = {    triggerCharacters = { " ", "~", "?", ":", "(" }  },  textDocumentSync = {    change = 2,    openClose = true,    save = true,    willSave = false,    willSaveWaitUntil = false  },  typeDefinitionProvider = true,  workspace = {    workspaceFolders = {      changeNotifications = true,      supported = true    }  },  workspaceSymbolProvider = true}
[INFO][2022-05-08 18:43:57] .../lua/vim/lsp.lua:983	"LSP[ocamllsp]"	"initialized"	{  resolved_capabilities = {    call_hierarchy = false,    code_action = {      codeActionKinds = { "quickfix", "construct", "destruct", "inferred_intf", "put module name in identifiers", "remove module name from identifiers", "type-annotate" }    },    code_lens = true,    code_lens_resolve = false,    completion = true,    declaration = true,    document_formatting = true,    document_highlight = true,    document_range_formatting = false,    document_symbol = true,    execute_command = true,    find_references = true,    goto_definition = true,    hover = true,    implementation = false,    rename = true,    signature_help = true,    signature_help_trigger_characters = { " ", "~", "?", ":", "(" },    text_document_did_change = 2,    text_document_open_close = true,    text_document_save = true,    text_document_save_include_text = false,    text_document_will_save = false,    text_document_will_save_wait_until = false,    type_definition = true,    workspace_folder_properties = {      changeNotifications = true,      supported = true    },    workspace_symbol = true  }}
[DEBUG][2022-05-08 18:43:57] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didOpen",  params = {    textDocument = {      languageId = "ocaml",      text = 'open Ppxlib\nopen Ast_pattern\n\nlet pat = pstr ((pstr_value nonrecursive ((value_binding ~pat:ppat_any ~expr:__) ^:: nil)) ^:: nil)\n\nlet test =\n  let expand ~loc ~path:_ e =\n    let loc = { loc with loc_ghost = true } in\n    match Sys.getenv_opt "RELEASE" with\n    | Some _ -> Attribute.explicitly_drop#expression e; [%str ]\n    | None -> [%str let () = if Sys.getenv_opt "DO_TEST" <> None then [%e e]]\n  in\n  Extension.declare_inline "ppx.test"\n    Extension.Context.structure_item\n    pat\n    expand\n\nlet () = Driver.register_transformation "ppx" ~extensions:[test]\n',      uri = "file:///tmp/1/ppx.ml",      version = 0    }  }}
[DEBUG][2022-05-08 18:43:58] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = {},    uri = "file:///tmp/1/ppx.ml"  }}
[DEBUG][2022-05-08 18:43:59] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didOpen",  params = {    textDocument = {      languageId = "ocaml",      text = "let%test _ = assert true\n",      uri = "file:///tmp/1/test.ml",      version = 0    }  }}
[DEBUG][2022-05-08 18:43:59] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = {},    uri = "file:///tmp/1/test.ml"  }}
[DEBUG][2022-05-08 18:44:02] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didChange",  params = {    contentChanges = { {        range = {          end = {            character = 0,            line = 1          },          start = {            character = 24,            line = 0          }        },        rangeLength = 1,        text = "\n\n"      }, {        range = {          end = {            character = 0,            line = 1          },          start = {            character = 0,            line = 1          }        },        rangeLength = 0,        text = "  "      }, {        range = {          end = {            character = 2,            line = 1          },          start = {            character = 1,            line = 1          }        },        rangeLength = 1,        text = ""      }, {        range = {          end = {            character = 1,            line = 1          },          start = {            character = 0,            line = 1          }        },        rangeLength = 1,        text = ""      } },    textDocument = {      uri = "file:///tmp/1/test.ml",      version = 6    }  }}
[DEBUG][2022-05-08 18:44:02] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = {},    uri = "file:///tmp/1/test.ml"  }}
[DEBUG][2022-05-08 18:44:03] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didChange",  params = {    contentChanges = { {        range = {          end = {            character = 0,            line = 2          },          start = {            character = 0,            line = 1          }        },        rangeLength = 1,        text = ""      } },    textDocument = {      uri = "file:///tmp/1/test.ml",      version = 8    }  }}
[DEBUG][2022-05-08 18:44:03] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = { {        message = "Uninterpreted extension 'test'.",        range = {          end = {            character = 8,            line = 0          },          start = {            character = 4,            line = 0          }        },        severity = 1,        source = "ocamllsp"      } },    uri = "file:///tmp/1/test.ml"  }}
[DEBUG][2022-05-08 18:44:14] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "textDocument/didSave",  params = {    textDocument = {      uri = "file:///tmp/1/test.ml"    }  }}
[DEBUG][2022-05-08 18:44:14] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = { {        message = "Uninterpreted extension 'test'.",        range = {          end = {            character = 8,            line = 0          },          start = {            character = 4,            line = 0          }        },        severity = 1,        source = "ocamllsp"      } },    uri = "file:///tmp/1/test.ml"  }}
[START][2022-05-08 18:43:47] LSP logging initiated
[INFO][2022-05-08 18:44:16] .../lua/vim/lsp.lua:1392	"exit_handler"	{}
[INFO][2022-05-08 18:44:26] .../lua/vim/lsp.lua:1392	"exit_handler"	{ {    _on_attach = <function 1>,    attached_buffers = { true,      [3] = true    },    cancel_request = <function 2>,    commands = {},    config = {      autostart = true,      capabilities = {        callHierarchy = {          dynamicRegistration = false        },        textDocument = {          codeAction = {            codeActionLiteralSupport = {              codeActionKind = {                valueSet = { "", "Empty", "QuickFix", "Refactor", "RefactorExtract", "RefactorInline", "RefactorRewrite", "Source", "SourceOrganizeImports", "quickfix", "refactor", "refactor.extract", "refactor.inline", "refactor.rewrite", "source", "source.organizeImports" }              }            },            dataSupport = true,            dynamicRegistration = false,            resolveSupport = {              properties = { "edit" }            }          },          completion = {            completionItem = {              commitCharactersSupport = false,              deprecatedSupport = false,              documentationFormat = { "markdown", "plaintext" },              preselectSupport = false,              snippetSupport = false            },            completionItemKind = {              valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }            },            contextSupport = false,            dynamicRegistration = false          },          declaration = {            linkSupport = true          },          definition = {            linkSupport = true          },          documentHighlight = {            dynamicRegistration = false          },          documentSymbol = {            dynamicRegistration = false,            hierarchicalDocumentSymbolSupport = true,            symbolKind = {              valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }            }          },          hover = {            contentFormat = { "markdown", "plaintext" },            dynamicRegistration = false          },          implementation = {            linkSupport = true          },          publishDiagnostics = {            relatedInformation = true,            tagSupport = {              valueSet = { 1, 2 }            }          },          references = {            dynamicRegistration = false          },          rename = {            dynamicRegistration = false,            prepareSupport = true          },          signatureHelp = {            dynamicRegistration = false,            signatureInformation = {              activeParameterSupport = true,              documentationFormat = { "markdown", "plaintext" },              parameterInformation = {                labelOffsetSupport = true              }            }          },          synchronization = {            didSave = true,            dynamicRegistration = false,            willSave = false,            willSaveWaitUntil = false          },          typeDefinition = {            linkSupport = true          }        },        window = {          showDocument = {            support = false          },          showMessage = {            messageActionItem = {              additionalPropertiesSupport = false            }          },          workDoneProgress = true        },        workspace = {          applyEdit = true,          configuration = true,          symbol = {            dynamicRegistration = false,            hierarchicalWorkspaceSymbolSupport = true,            symbolKind = {              valueSet = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }            }          },          workspaceEdit = {            resourceOperations = { "rename", "create", "delete" }          },          workspaceFolders = true        }      },      cmd = { "ocamllsp" },      cmd_cwd = "/tmp/1",      cmd_env = {        OCAMLLSP_DEBUG = "1"      },      filetypes = { "ocaml", "ocaml.menhir", "ocaml.interface", "ocaml.ocamllex", "reason" },      flags = {},      get_language_id = <function 3>,      handlers = <1>{},      init_options = vim.empty_dict(),      log_level = 2,      message_level = 2,      name = "ocamllsp",      on_attach = <function 4>,      on_exit = <function 5>,      on_init = <function 6>,      root_dir = "/tmp/1",      settings = vim.empty_dict(),      workspace_folders = <2>{ {          name = "/tmp/1",          uri = "file:///tmp/1"        } },      <metatable> = <3>{        __tostring = <function 7>      }    },    handlers = <table 1>,    id = 1,    initialized = true,    is_stopped = <function 8>,    messages = {      messages = {},      name = "ocamllsp",      progress = {},      status = {}    },    name = "ocamllsp",    notify = <function 9>,    offset_encoding = "utf-16",    request = <function 10>,    request_sync = <function 11>,    requests = {},    resolved_capabilities = {      call_hierarchy = false,      code_action = <4>{        codeActionKinds = { "quickfix", "construct", "destruct", "inferred_intf", "put module name in identifiers", "remove module name from identifiers", "type-annotate" }      },      code_lens = true,      code_lens_resolve = false,      completion = true,      declaration = true,      document_formatting = true,      document_highlight = true,      document_range_formatting = false,      document_symbol = true,      execute_command = true,      find_references = true,      goto_definition = true,      hover = true,      implementation = false,      rename = true,      signature_help = true,      signature_help_trigger_characters = <5>{ " ", "~", "?", ":", "(" },      text_document_did_change = 2,      text_document_open_close = true,      text_document_save = true,      text_document_save_include_text = false,      text_document_will_save = false,      text_document_will_save_wait_until = false,      type_definition = true,      workspace_folder_properties = {        changeNotifications = true,        supported = true      },      workspace_symbol = true    },    rpc = {      handle = <userdata 1>,      notify = <function 12>,      pid = 63502,      request = <function 13>    },    server_capabilities = {      codeActionProvider = <table 4>,      codeLensProvider = {        resolveProvider = false      },      completionProvider = {        resolveProvider = true,        triggerCharacters = { ".", "#" }      },      declarationProvider = true,      definitionProvider = true,      documentFormattingProvider = true,      documentHighlightProvider = true,      documentSymbolProvider = true,      executeCommandProvider = {        commands = { "dune/promote" }      },      experimental = {        ocamllsp = {          diagnostic_promotions = true,          handleInferIntf = true,          handleSwitchImplIntf = true,          handleTypedHoles = true,          handleWrappingAstNode = true,          interfaceSpecificLangId = true        }      },      foldingRangeProvider = true,      hoverProvider = true,      referencesProvider = true,      renameProvider = {        prepareProvider = true      },      selectionRangeProvider = true,      signatureHelpProvider = {        triggerCharacters = <table 5>      },      textDocumentSync = {        change = 2,        openClose = true,        save = true,        willSave = false,        willSaveWaitUntil = false      },      typeDefinitionProvider = true,      workspace = {        workspaceFolders = {          changeNotifications = true,          supported = true        }      },      workspaceSymbolProvider = true    },    stop = <function 14>,    supports_method = <function 15>,    workspaceFolders = <table 2>,    workspace_did_change_configuration = <function 16>,    workspace_folders = <table 2>  } }
[DEBUG][2022-05-08 18:44:26] .../vim/lsp/rpc.lua:347	"rpc.send"	{  id = 2,  jsonrpc = "2.0",  method = "shutdown"}
[DEBUG][2022-05-08 18:44:26] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  id = 2,  jsonrpc = "2.0"}
[DEBUG][2022-05-08 18:44:26] .../vim/lsp/rpc.lua:347	"rpc.send"	{  jsonrpc = "2.0",  method = "exit"}
@copy
Copy link
Author

copy commented May 31, 2022

Trying to narrow this down, since it makes it quite difficult to work with ppxs in my monorepo:

I added the following here to check if merlin is being invoked with the correct ppx and that the ppx is built:

      let ppx = config.ocaml.ppx in
      List.iter ~f:(fun x ->
          let f = List.hd (String.split_on_char ~sep:' ' x.Merlin_utils.Std.workval) in
          Printf.eprintf "XXX %s %b\n%!" x.workval (Sys.file_exists f);
        ) ppx;
      Printf.eprintf "XXX %s\n%!" (Merlin_utils.Std.Json.to_string (Mconfig.dump config));

I also added logging to make sure that the diagnostic is actually coming from merlin.

[ERROR][2022-05-31 17:02:57] .../vim/lsp/rpc.lua:420	"rpc"	"/home/fabian/ocaml/not-mine/ocaml-lsp/_build/default/ocaml-lsp-server/bin/main.exe"	"stderr"	'XXX /tmp/1/_build/default/.ppx/98cd9c27bc47def1a842c7a721af4e6b/ppx.exe --as-ppx true\nXXX {"ocaml":{"include_dirs":[],"no_std_include":false,"unsafe":false,"classic":false,"principal":false,"real_paths":false,"recursive_types":false,"strict_sequence":true,"applicative_functors":true,"unsafe_string":false,"nopervasives":false,"strict_formats":true,"open_modules":[],"ppx":[{"workdir":"/tmp/1","workval":"/tmp/1/_build/default/.ppx/98cd9c27bc47def1a842c7a721af4e6b/ppx.exe --as-ppx"}],"pp":null,"warnings":{"actives":[1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,30,31,32,33,34,35,36,37,38,39,43,46,47,49,50,51,52,53,54,55,56,57,58,59,61,62,63,64,65,71,72],"warn_error":[1,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,30,31,32,33,34,35,36,37,38,39,43,46,47,49,50,51,52,53,54,55,56,57,61,62],"alerts":{"alerts":[],"complement":true},"alerts_error":{"alerts":["deprecated"],"complement":false}}},"merlin":{"build_path":["/tmp/1/_build/default/.test.eobjs/byte"],"source_path":["/tmp/1"],"cmi_path":[],"cmt_path":[],"flags_applied":[{"workdir":"/tmp/1","workval":["-ppx","/tmp/1/_build/default/.ppx/98cd9c27bc47def1a842c7a721af4e6b/ppx.exe --as-ppx"]},{"workdir":"/tmp/1","workval":["-w","@[email protected]@30..39@[email protected]@[email protected]","-strict-sequence","-strict-formats","-short-paths","-keep-locs"]}],"extensions":[],"suffixes":[{"impl":".ml","intf":".mli"},{"impl":".re","intf":".rei"}],"stdlib":"/home/fabian/.opam/4.14.0/lib/ocaml","reader":[],"protocol":"json","log_file":null,"log_sections":[],"flags_to_apply":[],"failures":[],"assoc_suffixes":[{"extension":".re","reader":"reason"},{"extension":".rei","reader":"reason"}]},"query":{"filename":"test.ml","directory":"/tmp/1","printer_width":0,"verbosity":0}}\n'
[ERROR][2022-05-31 17:02:57] .../vim/lsp/rpc.lua:420	"rpc"	"/home/fabian/ocaml/not-mine/ocaml-lsp/_build/default/ocaml-lsp-server/bin/main.exe"	"stderr"	"XXX MERLIN DIAG: Uninterpreted extension 'test'.\n"
[DEBUG][2022-05-31 17:02:57] .../vim/lsp/rpc.lua:454	"rpc.receive"	{  jsonrpc = "2.0",  method = "textDocument/publishDiagnostics",  params = {    diagnostics = { {        message = "Uninterpreted extension 'test'.",        range = {          end = {            character = 8,            line = 0          },          start = {            character = 4,            line = 0          }        },        severity = 1,        source = "ocamllsp"      } },    uri = "file:///tmp/1/test.ml"  }}

Resulting config:

{
    "ocaml": {
        "include_dirs": [],
        "no_std_include": false,
        "unsafe": false,
        "classic": false,
        "principal": false,
        "real_paths": false,
        "recursive_types": false,
        "strict_sequence": true,
        "applicative_functors": true,
        "unsafe_string": false,
        "nopervasives": false,
        "strict_formats": true,
        "open_modules": [],
        "ppx": [{
            "workdir": "/tmp/1",
            "workval": "/tmp/1/_build/default/.ppx/98cd9c27bc47def1a842c7a721af4e6b/ppx.exe --as-ppx"
        }],
        "pp": null,
        "warnings": {
            "actives": [1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 63, 64, 65, 71, 72],
            "warn_error": [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 43, 46, 47, 49, 50, 51, 52, 53, 54, 55, 56, 57, 61, 62],
            "alerts": {
                "alerts": [],
                "complement": true
            },
            "alerts_error": {
                "alerts": ["deprecated"],
                "complement": false
            }
        }
    },
    "merlin": {
        "build_path": ["/tmp/1/_build/default/.test.eobjs/byte"],
        "source_path": ["/tmp/1"],
        "cmi_path": [],
        "cmt_path": [],
        "flags_applied": [{
            "workdir": "/tmp/1",
            "workval": ["-ppx", "/tmp/1/_build/default/.ppx/98cd9c27bc47def1a842c7a721af4e6b/ppx.exe --as-ppx"]
        }, {
            "workdir": "/tmp/1",
            "workval": ["-w", "@[email protected]@30..39@[email protected]@[email protected]", "-strict-sequence", "-strict-formats", "-short-paths", "-keep-locs"]
        }],
        "extensions": [],
        "suffixes": [{
            "impl": ".ml",
            "intf": ".mli"
        }, {
            "impl": ".re",
            "intf": ".rei"
        }],
        "stdlib": "/home/fabian/.opam/4.14.0/lib/ocaml",
        "reader": [],
        "protocol": "json",
        "log_file": null,
        "log_sections": [],
        "flags_to_apply": [],
        "failures": [],
        "assoc_suffixes": [{
            "extension": ".re",
            "reader": "reason"
        }, {
            "extension": ".rei",
            "reader": "reason"
        }]
    },
    "query": {
        "filename": "test.ml",
        "directory": "/tmp/1",
        "printer_width": 0,
        "verbosity": 0
    }
}

Unfortunately, everything looks correct. The correct ppx is being passed to merlin, as per dune rules:

((deps
  ((File
    (In_build_dir
     _build/default/.ppx/98cd9c27bc47def1a842c7a721af4e6b/ppx.exe))
   (File (In_build_dir _build/default/test.ml))))
 (targets ((In_build_dir _build/default/test.pp.ml)))
 (context default)
 (action
  (chdir
   _build/default
   (progn
    (chdir
     .
     (run
      .ppx/98cd9c27bc47def1a842c7a721af4e6b/ppx.exe
      -o
      test.pp.ml
      --impl
      test.ml
      -corrected-suffix
      .ppx-corrected
      -diff-cmd
      -
      -dump-ast))
    (diff? test.ml test.ml.ppx-corrected)))))

The error is the same as running ocaml without a ppx. What could cause merlin to "skip" the ppx, or how could I narrow it down further?

@rgrinberg
Copy link
Member

One thing that would help narrow this down: is it an issue with regular merlin?

@copy
Copy link
Author

copy commented May 31, 2022

No, with regular merlin the issue doesn't happen.

@copy
Copy link
Author

copy commented May 31, 2022

Narrowing it down further, I logged the potential exception that is caught in merlin's ppx code (here):

      let caught = ref [] in
      Msupport.catch_errors Mconfig.(config.ocaml.warnings) caught @@ fun () ->
      Printf.eprintf "XXX CONFIG IN MPIPELINE: %s\n%!" (Json.to_string (Mconfig.dump config));
      let parsetree = Mppx.rewrite config parsetree in
      List.iter (fun e -> Printf.eprintf "EXCEPTION: %s\n%!" (Printexc.to_string e)) !caught;
      { Ppx. config; parsetree; errors = !caught }

And it prints:

"EXCEPTION: Sys_error(\"cd '/tmp/1' && /tmp/1/_build/default/.ppx/d7394c27c5e0f7ad7ab1110d6b092c05/ppx.exe --as-ppx '/tmp/camlppxb9d449' '/tmp/camlppxb579b9' 1>&2: No child process\")

@rgrinberg
Copy link
Member

Try this fix:

diff --git a/src/ocaml/driver/pparse.ml b/src/ocaml/driver/pparse.ml
index ab397e93..1679a05a 100644
--- a/src/ocaml/driver/pparse.ml
+++ b/src/ocaml/driver/pparse.ml
@@ -46,7 +46,7 @@ let merlin_system_command =
     windows_merlin_system_command
   else
     fun cmd ~cwd ->
-      Sys.command (Printf.sprintf "cd %s && %s" (Filename.quote cwd) cmd)
+      Sys.command (Printf.sprintf "cd %s && %s" (Filename.quote_command cwd) cmd)
 
 let ppx_commandline cmd fn_in fn_out =
   Printf.sprintf "%s %s %s%s"

@rgrinberg
Copy link
Member

rgrinberg commented May 31, 2022

In the vendored submodule of merlin in ocamllsp

@rgrinberg
Copy link
Member

Actually, never mind. I think I understand the issue. The scheduler is calling waitpid and that's probably reaping it for the ppx.

@rgrinberg rgrinberg added this to the 1.12.0 milestone May 31, 2022
@rgrinberg rgrinberg modified the milestones: 1.12.0, 1.13.0, 1.12.1 Jun 20, 2022
@rgrinberg
Copy link
Member

Try #735 and let me know if it fixes the issue.

@copy
Copy link
Author

copy commented Jun 23, 2022

I can confirm that #735 fixes the issue for me.

rgrinberg added a commit to rgrinberg/opam-repository that referenced this issue Jun 23, 2022
CHANGES:

## Fixes

- Fix preprocessing, ppx, and reason support (ocaml/ocaml-lsp#735 fixes ocaml/ocaml-lsp#696, ocaml/ocaml-lsp#706)

- Support `include` in folding ranges (ocaml/ocaml-lsp#730)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants