Repository: ocaml/merlin

Issue #894: MerlinLocate not resolving definition of core modules
Created: 2018-12-28T02:25:28Z
If I have an OCaml file as follows:
open Core
module L = List
...

and I try to MerlinLocate on List, I get the following error:
Several source files in your path have the same name, and merlin doesn't know which is the right one:
/usr/local/lib/ocaml/list.ml, /usr/local/lib/ocaml/list.mli, /Users/dani/.opam/system/lib/core_kernel/
list.ml, /Users/dani/.opam/system/lib/core_kernel/list.mli, /Users/dani/.opam/system/lib/base/list.ml,
 /Users/dani/.opam/system/lib/base/list.mli

Why is Merlin having trouble selecting the right one? I'm using Merlin version 3.2.2.
(Following up on issue 2 in #863. The behavior I had been seeing was that this issue occurred when trying to go to definition a second time, as though the locate was cached and there was an issue with the cached version, but now the issue happens even on the first locate request)

Duplicate issue #877: Inconsistent merlin-locate behavior
Created: 2018-10-28T18:40:27Z
Using:
The Merlin toolkit version e14597b2a6, for Ocaml 4.07.1

...and given this example (taken directly from the cohttp readme:
open Lwt
open Cohttp
open Cohttp_lwt_unix

let body =
  Client.get (Uri.of_string "https://www.reddit.com/") >>= fun (resp, body) ->
  let code = resp |> Response.status |> Code.code_of_status in
  Printf.printf "Response code: %d\n" code;
  Printf.printf "Headers: %s\n" (resp |> Response.headers |> Header.to_string);
  body |> Cohttp_lwt.Body.to_string >|= fun body ->
  Printf.printf "Body of length: %d\n" (String.length body);
  body

let () =
  let body = Lwt_main.run body in
  print_endline ("Received body\n" ^ body)
...and this .merlin file (note, the bug still happens if you include lwt and cohttp-lwt in the list):
PKG cohttp-lwt-unix

...I get the following message in both Emacs and vim if I try to merlin-locate or :MerlinLocate the get on line 6 (Client.get):
Several source files in your path have the same name, and merlin doesn't know which is the right one: /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt-unix/client.ml, /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt/client.ml
At first I thought this was because merlin was perhaps doing something like falling back to gluing filesystem paths together based on e.g. -I /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt-unix -I /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt if it was unable to use the relevant compiler infrastructure to establish the canonical file containing the definition of module Client (resolving things like aliases, functor application, include, etc., of course), but this did not seem to be the case, as testing from the command line worked fine:
arch-vm[1219]:~/prog/ocaml/client_example% ocamlmerlin single locate -position 6:9 -look-for ml -- -I "$(ocamlfind query cohttp-lwt)" -I "$(ocamlfind query cohttp-lwt-unix)" client_example.ml < client_example.ml
{"class":"return","value":{"file":"/home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt-unix/client.ml","pos":{"line":2,"col":0}},"notifications":[],"timing":{"total":9.444000000000001,"query":1.3689999999999998,"reader":0.28800000000000026,"ppx":0.025999999999998025,"typer":7.761000000000003,"error":0.0}}

So I decided to check what was actually being sent by Emacs; the debug dump is attached, as it is long, but it seems merlin does do what I suspect if it for whatever reason cannot precisely determine what file contains the definition of some identifier. First, this happens:
# 0.09 locate - from_string
looking for the source of 'Client.get' (prioritizing .ml files)
# 0.09 locate - lookup
lookup in value namespace
# 0.09 locate - locate
present in the environment, walking up the typedtree looking for 'Cohttp_lwt_unix/0.Client.get[val]'

But later, this happens:
# 0.10 locate - find_source(Client)
multiple matches in the source path : /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt-unix/client.ml , /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt/client.ml
# 0.10 locate - find_source
... trying to use source digest to find the right one
# 0.10 locate - find_source
Source digest: 1c95318860ee5a485ce3e53e86882f4d
# 0.10 locate - find_source
  /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt-unix/client.ml (71d00f05903bfd817bfbb05093e9ae8e)
# 0.10 locate - find_source
  /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt/client.ml (be192f9377e87a82c333e9b9abe98cdb)
# 0.10 locate - find_source
... using heuristic to select the right one
# 0.10 locate - find_source
we are looking for a file named cohttp-lwt-unix/src/client.ml in /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt-unix
# 0.10 stat_cache - reuse cache
/home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt-unix/client.ml
# 0.10 stat_cache - reuse cache
/home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt/client.ml
# 0.10 locate - result
not found
# 0.10 New_commands.run - result
"Several source files in your path have the same name, and merlin doesn't know which is the right one: /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt-unix/client.ml, /home/mdl/.opam/4.07.1+flambda/lib/cohttp-lwt/client.ml"

I am not sure why locate is trying to do some sort of find_source(Client) step when ocamlmerlin has been invoked as in the log vs. the way I tested at the command line, given that it seems to find what it needs based on the log output (i.e. when run from Emacs). Here is the full log: merlin-log.txt
You can test this for yourself if you install cohttp-lwt.1.2.0 and cohttp-lwt-unix.1.2.0 from opam. I suspect the mix of aliasing and functor application from cohttp-lwt-unix/client.ml to cohttp-lwt/cohttp_lwt.ml to cohttp-lwt/client.ml eventually confuses merlin, but I have already babbled enough!

Closing comment (2019-08-09T01:44:55Z): I am having this issue as well, and I think it is the same as #894.
$ ocamlmerlin -version
The Merlin toolkit version ddf678dd, for Ocaml 4.08.0

I can provide more info upon request.
(ping @let-def)