Skip to content

Commit 4eb93fd

Browse files
authored
fix(rules): canonical paths in aliases (#6963)
The canonical paths were all wrong for modules with (include_subdirs qualified). This PR addresses the problem. Signed-off-by: Rudi Grinberg <[email protected]>
1 parent d5fa2d3 commit 4eb93fd

File tree

5 files changed

+130
-71
lines changed

5 files changed

+130
-71
lines changed

src/dune_rules/module_compilation.ml

+25-29
Original file line numberDiff line numberDiff line change
@@ -359,26 +359,23 @@ module Alias_module = struct
359359

360360
type alias =
361361
{ local_name : Module_name.t
362+
; canonical_path : Module_name.Path.t
362363
; obj_name : Module_name.Unique.t
363364
}
364365

365366
type t =
366-
{ main_module : Module_name.t option
367-
; aliases : alias list
367+
{ aliases : alias list
368368
; shadowed : Module_name.t list
369369
}
370370

371-
let to_ml { main_module; aliases; shadowed } =
371+
let to_ml { aliases; shadowed } =
372372
let b = Buffer.create 16 in
373373
Buffer.add_string b "(* generated by dune *)\n";
374-
let main_module = main_module |> Option.map ~f:Module_name.to_string in
375-
List.iter aliases ~f:(fun { local_name; obj_name } ->
376-
let local_name = Module_name.to_string local_name in
377-
(match main_module with
378-
| None -> ()
379-
| Some main_module ->
380-
Printf.bprintf b "\n(** @canonical %s.%s *)" main_module local_name);
381-
Printf.bprintf b "\nmodule %s = %s\n" local_name
374+
List.iter aliases ~f:(fun { canonical_path; local_name; obj_name } ->
375+
Printf.bprintf b "\n(** @canonical %s *)"
376+
(Module_name.Path.to_string canonical_path);
377+
Printf.bprintf b "\nmodule %s = %s\n"
378+
(Module_name.to_string local_name)
382379
(Module_name.Unique.to_name ~loc:Loc.none obj_name
383380
|> Module_name.to_string));
384381
List.iter shadowed ~f:(fun shadowed ->
@@ -389,33 +386,32 @@ module Alias_module = struct
389386
(Module_name.to_string shadowed));
390387
Buffer.contents b
391388

392-
let of_modules project modules ~alias_module ~group =
393-
let main_module = Modules.main_module_name modules in
389+
let of_modules project modules group =
394390
let aliases =
395-
Module_name.Map.to_list_map group ~f:(fun local_name m ->
396-
let obj_name = Module.obj_name m in
397-
{ local_name; obj_name })
391+
Modules.Group.for_alias group
392+
|> List.map ~f:(fun (local_name, m) ->
393+
let canonical_path = Modules.canonical_path modules group m in
394+
let obj_name = Module.obj_name m in
395+
{ canonical_path; local_name; obj_name })
398396
in
399397
let shadowed =
400398
if Dune_project.dune_version project < (3, 5) then []
401399
else
402-
match Modules.lib_interface modules with
403-
| None -> []
404-
| Some m -> (
405-
match Module.kind m with
406-
| Alias _ -> []
407-
| _ -> [ Module.name alias_module ])
400+
let lib_interface = Modules.Group.lib_interface group in
401+
match Module.kind lib_interface with
402+
| Alias _ -> []
403+
| _ -> [ Module.name (Modules.Group.alias group) ]
408404
in
409-
{ main_module; aliases; shadowed }
405+
{ aliases; shadowed }
410406
end
411407

412-
let build_alias_module cctx alias_module group =
413-
let modules = Compilation_context.modules cctx in
408+
let build_alias_module cctx group =
414409
let alias_file () =
415410
let project = Compilation_context.scope cctx |> Scope.project in
416-
Alias_module.of_modules project modules ~alias_module ~group
417-
|> Alias_module.to_ml
411+
let modules = Compilation_context.modules cctx in
412+
Alias_module.of_modules project modules group |> Alias_module.to_ml
418413
in
414+
let alias_module = Modules.Group.alias group in
419415
let cctx = Compilation_context.for_alias_module cctx alias_module in
420416
let sctx = Compilation_context.super_context cctx in
421417
let file = Option.value_exn (Module.file alias_module ~ml_kind:Impl) in
@@ -460,9 +456,9 @@ let build_all cctx =
460456
Memo.parallel_iter
461457
(Modules.fold_no_vlib_with_aliases modules ~init:[]
462458
~normal:(fun x acc -> `Normal x :: acc)
463-
~alias:(fun m group acc -> `Alias (m, group) :: acc))
459+
~alias:(fun group acc -> `Alias group :: acc))
464460
~f:(function
465-
| `Alias (m, group) -> build_alias_module cctx m group
461+
| `Alias group -> build_alias_module cctx group
466462
| `Normal m -> (
467463
match Module.kind m with
468464
| Alias _ -> assert false

src/dune_rules/modules.ml

+88-37
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,12 @@ module Mangle = struct
207207
| None -> base
208208
| Some prefix -> prefix :: base
209209
in
210-
let name = Module_name.Unique.to_name ~loc:Loc.none obj_name in
211-
let path = if has_lib_interface then [ name ] else interface :: path in
210+
let name =
211+
if has_lib_interface then
212+
Module_name.Unique.to_name ~loc:Loc.none obj_name
213+
else interface
214+
in
215+
let path = if has_lib_interface then [ name ] else path @ [ interface ] in
212216
Module.generated ~path ~obj_name ~kind ~src_dir name
213217

214218
let wrap_module t m ~interface =
@@ -246,6 +250,8 @@ module Group = struct
246250
| Group of t
247251
| Module of Module.t
248252

253+
let alias t = t.alias
254+
249255
module Of_trie = struct
250256
let of_trie ~src_dir ~mangle ~interface ~rev_path trie =
251257
let rec loop interface rev_path trie =
@@ -477,34 +483,42 @@ module Group = struct
477483
match Module_name.Map.find modules name with
478484
| Some (Group g) -> g
479485
| Some (Module m) ->
480-
Code_error.raise "for_alias: unexpected module"
486+
Code_error.raise "group_of_alias: unexpected module"
481487
[ ("m", Module.to_dyn m); ("alias", Module.to_dyn alias) ]
482488
| None ->
483-
Code_error.raise "for_alias: not found"
484-
[ ("alias", Module.to_dyn alias) ]
489+
Code_error.raise "group_of_alias: not found"
490+
[ ("name", Module_name.to_dyn name)
491+
; ("modules", Module_name.Map.to_dyn dyn_of_node modules)
492+
; ("alias", Module.to_dyn alias)
493+
]
485494

486495
let path_of_alias_module alias =
487496
match Module.kind alias with
488497
| Alias for_ -> for_
489-
| _ -> Code_error.raise "for_alias: not an alias module" []
498+
| _ -> Code_error.raise "group_of_alias: not an alias module" []
490499

491-
let make_for_alias t alias path =
500+
let make_group_of_alias t alias path =
492501
let rec loop (t : t) = function
493502
| [] -> t
494503
| name :: path ->
495504
let group = find_module alias t.modules name in
496505
loop group path
497506
in
498-
let group = loop t path in
499-
let modules = Module_name.Map.remove group.modules group.name in
500-
Module_name.Map.map modules ~f:(fun (g : node) ->
501-
match g with
502-
| Module m -> m
503-
| Group g -> lib_interface g)
507+
loop t path
504508
end
505509

506-
let for_alias t alias =
507-
For_alias.make_for_alias t alias (For_alias.path_of_alias_module alias)
510+
let group_of_alias t alias =
511+
For_alias.make_group_of_alias t alias (For_alias.path_of_alias_module alias)
512+
513+
let for_alias t =
514+
Module_name.Map.remove t.modules t.name
515+
|> Module_name.Map.to_list_map ~f:(fun name node ->
516+
let m =
517+
match node with
518+
| Module m -> m
519+
| Group g -> lib_interface g
520+
in
521+
(name, m))
508522
end
509523

510524
module Unwrapped = struct
@@ -570,12 +584,12 @@ module Unwrapped = struct
570584
| Module m -> m
571585
| Group g -> Group.lib_interface g)
572586

573-
let for_alias t alias =
587+
let group_of_alias t alias =
574588
match Group.For_alias.path_of_alias_module alias with
575589
| [] -> assert false
576590
| name :: path ->
577591
let group = Group.For_alias.find_module alias t name in
578-
Group.For_alias.make_for_alias group alias path
592+
Group.For_alias.make_group_of_alias group alias path
579593

580594
module Memo_traversals = struct
581595
let parallel_map t ~f = Group.Memo_traversals.parallel_map_modules t ~f
@@ -611,7 +625,7 @@ module Wrapped = struct
611625
| Module m -> f m init
612626
| Group t -> Group.fold t ~f ~init)
613627

614-
let for_alias t m = Group.for_alias t.group m
628+
let group_of_alias t m = Group.group_of_alias t.group m
615629

616630
let encode { group; wrapped_compat; wrapped; toplevel_module = _ } =
617631
let open Dune_lang.Encoder in
@@ -920,25 +934,46 @@ let rec fold_no_vlib t ~init ~f =
920934
| Wrapped w -> Wrapped.fold w ~init ~f
921935
| Impl { vlib = _; impl } -> fold_no_vlib impl ~f ~init
922936

923-
let rec for_alias t m =
924-
match t with
925-
| Stdlib _ | Singleton _ -> Module_name.Map.empty
926-
| Unwrapped w -> Unwrapped.for_alias w m
927-
| Wrapped w -> Wrapped.for_alias w m
928-
| Impl { vlib; impl } ->
929-
let impl = for_alias impl m in
930-
let vlib = for_alias vlib m in
931-
Module_name.Map.merge impl vlib ~f:(fun _ impl vlib ->
932-
match (impl, vlib) with
933-
| None, None -> assert false
934-
| Some _, _ -> impl
935-
| _, Some vlib -> Option.some_if (Module.visibility vlib = Public) vlib)
936-
937-
let fold_no_vlib_with_aliases t ~init ~normal ~alias =
938-
fold_no_vlib t ~init ~f:(fun m acc ->
939-
match Module.kind m with
940-
| Alias _ -> alias m (for_alias t m) acc
941-
| _ -> normal m acc)
937+
let fold_no_vlib_with_aliases =
938+
let rec group_of_alias t m =
939+
match t with
940+
| Wrapped w -> Some (Wrapped.group_of_alias w m)
941+
| Unwrapped w -> Some (Unwrapped.group_of_alias w m)
942+
| Impl { vlib; impl } -> (
943+
let vlib = group_of_alias vlib m in
944+
let impl = group_of_alias impl m in
945+
match (vlib, impl) with
946+
| None, None -> assert false
947+
| Some _, None -> vlib
948+
| None, Some _ -> impl
949+
| Some vlib, Some impl ->
950+
let modules =
951+
Module_name.Map.merge vlib.modules impl.modules ~f:(fun _ vlib impl ->
952+
match (vlib, impl) with
953+
| None, None -> assert false
954+
| _, Some _ -> impl
955+
| Some vlib, _ ->
956+
let vlib =
957+
match (vlib : Group.node) with
958+
| Module m -> m
959+
| Group g -> Group.lib_interface g
960+
in
961+
Option.some_if (Module.visibility vlib = Public) vlib
962+
|> Option.map ~f:(fun m -> Group.Module m))
963+
in
964+
Some { impl with Group.modules })
965+
| _ -> None
966+
in
967+
fun t ~init ~normal ~alias ->
968+
fold_no_vlib t ~init ~f:(fun m acc ->
969+
match Module.kind m with
970+
| Alias _ -> (
971+
match group_of_alias t m with
972+
| None ->
973+
Code_error.raise "alias module for group without alias"
974+
[ ("t", to_dyn t); ("m", Module.to_dyn m) ]
975+
| Some group -> alias group acc)
976+
| _ -> normal m acc)
942977

943978
type split_by_lib =
944979
{ vlib : Module.t list
@@ -1131,3 +1166,19 @@ let source_dirs =
11311166
Module.sources m
11321167
|> List.fold_left ~init:acc ~f:(fun acc f ->
11331168
Path.Set.add acc (Path.parent_exn f)))
1169+
1170+
let canonical_path t (group : Group.t) m =
1171+
let path =
1172+
let path = Module.path m in
1173+
match Module_name.Map.find group.modules (Module.name m) with
1174+
| None | Some (Group.Module _) -> path
1175+
| Some (Group _) ->
1176+
(* The path for group interfaces always duplicates
1177+
the last component.
1178+
1179+
For example: foo/foo.ml would has the path [ "Foo"; "Foo" ] *)
1180+
path |> List.rev |> List.tl |> List.rev
1181+
in
1182+
match t with
1183+
| Impl { impl = Wrapped w; _ } | Wrapped w -> w.group.name :: path
1184+
| _ -> Module.path m

src/dune_rules/modules.mli

+13-1
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,23 @@ val singleton_exe : Module.t -> t
4545

4646
val fold_no_vlib : t -> init:'acc -> f:(Module.t -> 'acc -> 'acc) -> 'acc
4747

48+
module Group : sig
49+
type t
50+
51+
val alias : t -> Module.t
52+
53+
val lib_interface : t -> Module.t
54+
55+
val for_alias : t -> (Module_name.t * Module.t) list
56+
end
57+
58+
val canonical_path : t -> Group.t -> Module.t -> Module_name.Path.t
59+
4860
val fold_no_vlib_with_aliases :
4961
t
5062
-> init:'acc
5163
-> normal:(Module.t -> 'acc -> 'acc)
52-
-> alias:(Module.t -> Module.t Module_name.Map.t -> 'acc -> 'acc)
64+
-> alias:(Group.t -> 'acc -> 'acc)
5365
-> 'acc
5466

5567
val exe_unwrapped : Module.t Module_trie.t -> src_dir:Path.Build.t -> t

test/blackbox-tests/test-cases/include-qualified/basic.t/run.t

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ Basic test showcasing the feature. Every directory creates a new level of aliasi
1313
contents of _build/default/lib/foolib__Foo.ml-gen
1414
(* generated by dune *)
1515

16-
(** @canonical Foolib.A *)
16+
(** @canonical Foolib.Foo.A *)
1717
module A = Foolib__Foo__A
1818

19-
(** @canonical Foolib.Bar *)
19+
(** @canonical Foolib.Foo.Bar *)
2020
module Bar = Foolib__Foo__Bar
2121
--------
2222
contents of _build/default/lib/foolib__Foo__A.ml-gen
2323
(* generated by dune *)
2424

25-
(** @canonical Foolib.B *)
25+
(** @canonical Foolib.Foo.A.B *)
2626
module B = Foolib__Foo__A__B
2727
--------

test/blackbox-tests/test-cases/include-qualified/nested-lib-interface.t/run.t

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ We are also allowed to write lib interface files at each level.
2828
contents of _build/default/lib/foolib__Bar__.ml-gen
2929
(* generated by dune *)
3030

31-
(** @canonical Foolib.Baz *)
31+
(** @canonical Foolib.Bar.Baz *)
3232
module Baz = Foolib__Bar__Baz
3333

3434
module Foolib__Bar__ = struct end

0 commit comments

Comments
 (0)