Skip to content

Commit 2dbdb4d

Browse files
authored
Fix loader bug (#151)
* Fix loading of base * Format * Add change log entry
1 parent bfe1ad1 commit 2dbdb4d

File tree

3 files changed

+97
-43
lines changed

3 files changed

+97
-43
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
- Fixed initialization of the typing enviorment (#134, @azzsal)
4040
- Fix a bug the was causing the tool to stack overflow when dealing with
4141
some instances of parametrized types (#134, @azzsal)
42+
- Fix a bug where the loader couldn't find module types defined in the same
43+
compilation unit. (#151, @NathanReb, @azzsal)
4244

4345
### Removed
4446

lib/library.ml

Lines changed: 92 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@ let ( let> ) x f =
44
let mod_name file =
55
String.capitalize_ascii Filename.(remove_extension (basename file))
66

7+
let load_cmi file_path =
8+
try
9+
let cmi_infos = Cmi_format.read_cmi file_path in
10+
Ok (cmi_infos.cmi_sign, cmi_infos.cmi_name)
11+
with e ->
12+
Error
13+
(Printf.sprintf "Error parsing %s: %s" file_path (Printexc.to_string e))
14+
715
let lazy_sig path =
16+
let open CCResult.Infix in
817
Lazy.from_fun (fun () ->
9-
let cmi_infos = Cmi_format.read_cmi path in
10-
cmi_infos.cmi_sign)
18+
let+ cmi_sign, _ = load_cmi path in
19+
cmi_sign)
1120

1221
let collect_modules dir =
1322
try
@@ -26,13 +35,12 @@ let collect_modules dir =
2635
Error (Printf.sprintf "Error reading directory %s: %s" dir e)
2736

2837
let get_sig modname map =
29-
Option.map Lazy.force (String_map.find_opt modname map)
30-
31-
let load_cmi file_path =
32-
try
33-
let cmi_infos = Cmi_format.read_cmi file_path in
34-
Ok (cmi_infos.cmi_sign, cmi_infos.cmi_name)
35-
with e -> Error (Printexc.to_string e)
38+
let open CCResult.Infix in
39+
match String_map.find_opt modname map with
40+
| None -> Ok None
41+
| Some lazy_sig ->
42+
let* sig_ = Lazy.force lazy_sig in
43+
Ok (Some sig_)
3644

3745
type 'a named = { name : string; value : 'a }
3846
(** Attach a module name to its various representations, e.g. a [signature] or a
@@ -86,7 +94,7 @@ let find_module_item modname sig_ =
8694
| Some mty -> Ok mty
8795
| None -> lookup_error ~path:modname ~module_name:sig_.name
8896

89-
let find_module_type modname sig_ =
97+
let find_module_type_in_sig modname sig_ =
9098
let open Types in
9199
let mty_opt =
92100
List.find_map
@@ -101,21 +109,32 @@ let find_module_type modname sig_ =
101109
| Some mty -> Ok mty
102110
| None -> lookup_error ~path:modname ~module_name:sig_.name
103111

112+
let populate_env typing_env sig_ =
113+
List.fold_left
114+
(fun env sigi ->
115+
match sigi with
116+
| Types.Sig_modtype (id, modtype, Exported) ->
117+
Env.add_modtype id modtype env
118+
| _ -> env)
119+
typing_env sig_
120+
104121
let rec find_module_in_sig ~library_modules path sig_ =
105122
let open CCResult.Infix in
123+
let typing_env = populate_env Env.empty sig_.value in
106124
match (path : Flat_path.t) with
107125
| [ last ] ->
108126
let modname = Flat_path.modname_from_component last in
109127
find_module_item modname sig_
110128
| hd :: tl ->
111129
let modname = Flat_path.modname_from_component hd in
112130
let* mty = find_module_item modname sig_ in
113-
find_module_in_md_type ~library_modules tl { name = modname; value = mty }
131+
find_module_in_md_type ~typing_env ~library_modules tl
132+
{ name = modname; value = mty }
114133
| [] -> assert false
115134

116-
and find_module_in_md_type ~library_modules path mty =
135+
and find_module_in_md_type ~typing_env ~library_modules path mty =
117136
let open CCResult.Infix in
118-
let* sig_ = sig_of_module_type ~library_modules mty.value in
137+
let* sig_ = sig_of_module_type ~typing_env ~library_modules mty.value in
119138
match sig_ with
120139
| None ->
121140
let res =
@@ -137,48 +156,75 @@ and find_module_in_lib ~library_modules path :
137156
match path with
138157
| [ comp ] ->
139158
let modname = Flat_path.modname_from_component comp in
140-
let> sig_ = Ok (get_sig modname library_modules) in
159+
let> sig_ = get_sig modname library_modules in
141160
Ok (Some (Mty_signature sig_))
142-
| comp :: inner_path -> (
161+
| comp :: inner_path ->
143162
let modname = Flat_path.modname_from_component comp in
144-
match get_sig modname library_modules with
145-
| None -> Ok None
146-
| Some parent_sig ->
147-
let+ mty =
148-
find_module_in_sig ~library_modules inner_path
149-
{ name = modname; value = parent_sig }
150-
in
151-
Some mty)
163+
let> parent_sig = get_sig modname library_modules in
164+
let+ mty =
165+
find_module_in_sig ~library_modules inner_path
166+
{ name = modname; value = parent_sig }
167+
in
168+
Some mty
152169
| _ -> Ok None
153170

154-
and find_module_type_in_lib ~library_modules path :
155-
(Types.module_type option, string) result =
171+
and find_local_module_type ~typing_env path =
172+
try Some (`Local, Env.find_modtype_expansion path typing_env)
173+
with Not_found -> None
174+
175+
and find_global_module_type ~library_modules path =
176+
let typing_env = Env.empty in
156177
match path with
157178
| Path.Pdot (parent_mod_path, mty_name) ->
158179
let> parent_mod = find_module_in_lib ~library_modules parent_mod_path in
159-
let> sig_ = sig_of_module_type ~library_modules parent_mod in
160-
find_module_type mty_name { name = mty_name; value = sig_ }
180+
let> sig_ = sig_of_module_type ~typing_env ~library_modules parent_mod in
181+
let> mty =
182+
find_module_type_in_sig mty_name { name = mty_name; value = sig_ }
183+
in
184+
Ok (Some (`Global, mty))
161185
| _ -> assert false (* Path to module type cannot be root modules/functors *)
162186

163-
and sig_of_module_type ~library_modules module_type =
187+
and find_module_type ~typing_env ~library_modules path =
188+
match find_local_module_type ~typing_env path with
189+
| Some modtype -> Ok (Some modtype)
190+
| None -> find_global_module_type ~library_modules path
191+
192+
(*and find_module_type_in_lib ~library_modules ~typing_env path :
193+
(Types.module_type option, string) result =
194+
match (find_local_module_type ~typing_env path) with
195+
| Some x ->
196+
Ok (Some x)
197+
| None ->
198+
find_global_module_type ~library_modules
199+
*)
200+
and typing_env_for ~typing_env = function
201+
| `Local -> typing_env
202+
| `Global -> Env.empty
203+
204+
and sig_of_module_type ~library_modules ~typing_env module_type =
164205
match module_type with
165206
| Types.Mty_alias path ->
207+
(* find_module_in_lib only looks up globally, we shoud proabably fix it. *)
166208
let> mty = find_module_in_lib ~library_modules path in
167-
sig_of_module_type ~library_modules mty
209+
sig_of_module_type ~typing_env:Env.empty ~library_modules mty
168210
| Mty_ident path ->
169-
let> mty = find_module_type_in_lib ~library_modules path in
170-
sig_of_module_type ~library_modules mty
211+
let> where, mty = find_module_type ~typing_env ~library_modules path in
212+
let typing_env = typing_env_for ~typing_env where in
213+
sig_of_module_type ~typing_env ~library_modules mty
171214
| Mty_signature sig_ -> Ok (Some sig_)
172215
| Mty_functor _ -> Ok None
173216

174-
let rec expand_sig ~library_modules sig_ =
217+
let rec expand_sig ~typing_env ~library_modules sig_ =
175218
let open Types in
176219
let open CCResult.Infix in
220+
let typing_env = populate_env typing_env sig_ in
177221
CCResult.map_l
178222
(fun item ->
179223
match item with
180224
| Sig_module (id, presence, ({ md_type; _ } as mod_decl), rs, vis) ->
181-
let* md_type = expand_module_type ~library_modules md_type in
225+
let* md_type =
226+
expand_module_type ~typing_env ~library_modules md_type
227+
in
182228
let presence =
183229
match md_type with
184230
| Mty_alias _ -> presence
@@ -189,11 +235,11 @@ let rec expand_sig ~library_modules sig_ =
189235
| _ -> Ok item)
190236
sig_
191237

192-
and expand_module_type ~library_modules module_type =
238+
and expand_module_type ~typing_env ~library_modules module_type =
193239
let open CCResult.Infix in
194240
let+ res =
195-
let> sig_ = sig_of_module_type ~library_modules module_type in
196-
let+ expanded = expand_sig ~library_modules sig_ in
241+
let> sig_ = sig_of_module_type ~typing_env ~library_modules module_type in
242+
let+ expanded = expand_sig ~typing_env ~library_modules sig_ in
197243
Some (Types.Mty_signature expanded)
198244
in
199245
Option.value ~default:module_type res
@@ -203,24 +249,30 @@ type t = Types.signature String_map.t
203249
let load_unwrapped project_path : (t, string) result =
204250
let open CCResult.Infix in
205251
let* library_modules = collect_modules project_path in
206-
let module_map =
252+
let module_res_map =
207253
String_map.map (fun sig_ -> Lazy.force sig_) library_modules
208254
in
209-
Ok module_map
255+
String_map.fold
256+
(fun key value acc ->
257+
let* acc = acc in
258+
let* value = value in
259+
Ok (String_map.add key value acc))
260+
module_res_map (Ok String_map.empty)
210261

211262
let load ~main_module project_path : (t, string) result =
212263
let open CCResult.Infix in
213264
let* library_modules = collect_modules project_path in
214265
let* main_sig =
215-
match get_sig main_module library_modules with
266+
let* x = get_sig main_module library_modules in
267+
match x with
216268
| Some s -> Ok s
217269
| None ->
218270
Error
219271
(Printf.sprintf "Could not find main module %s in %s" main_module
220272
project_path)
221273
in
222274
let expanded_main_sig =
223-
match expand_sig ~library_modules main_sig with
275+
match expand_sig ~typing_env:Env.empty ~library_modules main_sig with
224276
| Ok expanded_sig -> expanded_sig
225277
| Error e -> failwith e
226278
in

tests/api-diff/errors.t

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ that it is ignored
2020
$ touch test2.cmi
2121
$ api-diff --main-module main test.cmi test2.cmi
2222
api-diff: --main-module is ignored when diffing single .cmi files
23-
api-diff: Cmi_format.Error(_)
23+
api-diff: Error parsing test.cmi: Cmi_format.Error(_)
2424
[123]
2525

2626
$ touch test2.cmi
2727
$ api-diff --unwrapped test.cmi test2.cmi
2828
api-diff: --unwrapped is ignored when diffing single .cmi files
29-
api-diff: Cmi_format.Error(_)
29+
api-diff: Error parsing test.cmi: Cmi_format.Error(_)
3030
[123]
3131

3232
$ touch test2.cmi
3333
$ api-diff --main-module main --unwrapped test.cmi test2.cmi
3434
api-diff: --main-module and --unwrapped are ignored when diffing single .cmi files
35-
api-diff: Cmi_format.Error(_)
35+
api-diff: Error parsing test.cmi: Cmi_format.Error(_)
3636
[123]

0 commit comments

Comments
 (0)