Skip to content

Commit 9492dce

Browse files
committed
Handle @canonical tags in the top-comment of signatures
Previously, @canonical tags were allowed to be attached to module, module type and type declarations and in the top-comment of compilation units. This handles @canonical tags in the top-comment of signatures and structures.
1 parent 8ec2332 commit 9492dce

File tree

4 files changed

+58
-25
lines changed

4 files changed

+58
-25
lines changed

src/loader/cmt.ml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,17 @@ and unwrap_module_expr_desc = function
387387
unwrap_module_expr_desc mexpr.mod_desc
388388
| desc -> desc
389389

390+
(** Like [read_module_expr] but handle the canonical tag in the top-comment. *)
391+
and read_module_expr_maybe_canonical env parent container ~canonical mexpr =
392+
let open ModuleType in
393+
match (canonical, mexpr.mod_desc) with
394+
| None, Tmod_structure str ->
395+
let sg, canonical =
396+
read_structure Odoc_model.Semantics.Expect_canonical env parent str
397+
in
398+
(Signature sg, canonical)
399+
| _ -> (read_module_expr env parent container mexpr, canonical)
400+
390401
and read_module_binding env parent mb =
391402
let open Module in
392403
#if OCAML_MAJOR = 4 && OCAML_MINOR >= 10
@@ -400,12 +411,17 @@ and read_module_binding env parent mb =
400411
let id = (id :> Identifier.Module.t) in
401412
let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in
402413
let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container mb.mb_attributes in
403-
let canonical = (canonical :> Path.Module.t option) in
404-
let type_ =
414+
let type_, canonical =
405415
match unwrap_module_expr_desc mb.mb_expr.mod_desc with
406-
| Tmod_ident(p, _) -> Alias (Env.Path.read_module env p, None)
407-
| _ -> ModuleType (read_module_expr env (id :> Identifier.Signature.t) container mb.mb_expr)
416+
| Tmod_ident (p, _) -> (Alias (Env.Path.read_module env p, None), canonical)
417+
| _ ->
418+
let id = (id :> Identifier.Signature.t) in
419+
let expr, canonical =
420+
read_module_expr_maybe_canonical env id container ~canonical mb.mb_expr
421+
in
422+
(ModuleType expr, canonical)
408423
in
424+
let canonical = (canonical :> Path.Module.t option) in
409425
let hidden =
410426
#if OCAML_MAJOR = 4 && OCAML_MINOR >= 10
411427
match canonical, mb.mb_id with

src/loader/cmti.ml

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -536,14 +536,35 @@ and read_module_type env parent label_parent mty =
536536
decl
537537
| Tmty_alias _ -> assert false
538538

539+
(** Like [read_module_type] but handle the canonical tag in the top-comment. If
540+
[canonical] is [Some _], no tag is expected in the top-comment. *)
541+
and read_module_type_maybe_canonical env parent container ~canonical mty =
542+
match (canonical, mty.mty_desc) with
543+
| None, Tmty_signature sg ->
544+
let sg, canonical =
545+
read_signature Odoc_model.Semantics.Expect_canonical env parent sg
546+
in
547+
(ModuleType.Signature sg, canonical)
548+
| _, _ -> (read_module_type env parent container mty, canonical)
549+
539550
and read_module_type_declaration env parent mtd =
540551
let open ModuleType in
541552
let id = Env.find_module_type env mtd.mtd_id in
542553
let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in
543554
let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container mtd.mtd_attributes in
555+
let expr, canonical =
556+
match mtd.mtd_type with
557+
| Some mty ->
558+
let expr, canonical =
559+
read_module_type_maybe_canonical env
560+
(id :> Identifier.Signature.t)
561+
container ~canonical mty
562+
in
563+
(Some expr, canonical)
564+
| None -> (None, canonical)
565+
in
544566
let canonical = (canonical :> Path.ModuleType.t option) in
545-
let expr = opt_map (read_module_type env (id :> Identifier.Signature.t) container) mtd.mtd_type in
546-
{id; doc; canonical; expr;}
567+
{ id; doc; canonical; expr }
547568

548569
and read_module_declaration env parent md =
549570
let open Module in
@@ -556,15 +577,20 @@ and read_module_declaration env parent md =
556577
let id = Env.find_module_identifier env md.md_id in
557578
#endif
558579
let id = (id :> Identifier.Module.t) in
559-
560580
let container = (parent : Identifier.Signature.t :> Identifier.LabelParent.t) in
561581
let doc, canonical = Doc_attr.attached Odoc_model.Semantics.Expect_canonical container md.md_attributes in
562-
let canonical = (canonical :> Path.Module.t option) in
563-
let type_ =
582+
let type_, canonical =
564583
match md.md_type.mty_desc with
565-
| Tmty_alias(p, _) -> Alias (Env.Path.read_module env p, None)
566-
| _ -> ModuleType (read_module_type env (id :> Identifier.Signature.t) container md.md_type)
584+
| Tmty_alias (p, _) -> (Alias (Env.Path.read_module env p, None), canonical)
585+
| _ ->
586+
let expr, canonical =
587+
read_module_type_maybe_canonical env
588+
(id :> Identifier.Signature.t)
589+
container ~canonical md.md_type
590+
in
591+
(ModuleType expr, canonical)
567592
in
593+
let canonical = (canonical :> Path.Module.t option) in
568594
let hidden =
569595
#if OCAML_MAJOR=4 && OCAML_MINOR >= 10
570596
match canonical, md.md_id with
@@ -576,7 +602,6 @@ and read_module_declaration env parent md =
576602
| _ -> false
577603
#endif
578604
in
579-
580605
Some {id; doc; type_; canonical; hidden}
581606

582607
and read_module_declarations env parent mds =

test/xref2/canonical_module_type.t/run.t

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ constructor where the second element of the tuple is Resolved.
2323

2424
$ ocamlc -c -bin-annot test.mli
2525
$ odoc compile --package x test.cmti
26-
File "test.mli", line 8, characters 6-24:
27-
Unexpected tag '@canonical' at this location.
2826
$ odoc link test.odoc
2927

3028
Every module type aliases and the path they link to:
3129

3230
$ odoc_print test.odocl | jq -c '.content.Module.items | .[] | select(.ModuleType.expr.Some.Path) | .ModuleType | { "from": .id, "to": .expr.Some.Path.p_path }'
33-
{"from":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"X"]},"to":{"`Resolved":{"`Identifier":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"B"]}}}}
31+
{"from":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"X"]},"to":{"`Resolved":{"`CanonicalModuleType":[{"`Identifier":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"B"]}},{"`Resolved":{"`Identifier":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"X"]}}}]}}}
3432
{"from":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"Y"]},"to":{"`Resolved":{"`CanonicalModuleType":[{"`Identifier":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"A"]}},{"`Resolved":{"`Identifier":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"Y"]}}}]}}}
3533
{"from":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"Z"]},"to":{"`Resolved":{"`CanonicalModuleType":[{"`Identifier":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"A"]}},{"`Resolved":{"`Identifier":{"`ModuleType":[{"`Root":[{"`RootPage":"x"},"Test"]},"Y"]}}}]}}}

test/xref2/canonical_unit.t/run.t

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,6 @@ The module Test_x is expected to be referenced as Test.X.
55
Test_w is similar but defined as a .ml file.
66

77
$ compile test_x.mli test_w.ml test.ml
8-
File "test_x.mli", line 13, characters 6-26:
9-
Unexpected tag '@canonical' at this location.
10-
File "test_w.ml", line 13, characters 6-26:
11-
Unexpected tag '@canonical' at this location.
12-
File "test.ml", line 18, characters 6-24:
13-
Unexpected tag '@canonical' at this location.
148

159
Test_x has a 'canonical' field:
1610

@@ -22,14 +16,14 @@ The first two type declarations should have resolved canonical constructors, the
2216
$ odoc_print test.odocl | jq -c ".content.Module.items | .[] | .Type[1] | select(.) | .equation.manifest.Some.Constr"
2317
[{"`Resolved":{"`Type":[{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"X"]}}]}}]},"t"]}},[]]
2418
[{"`Resolved":{"`Type":[{"`Canonical":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_y"]}},{"`Resolved":{"`Alias":[{"`Canonical":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_y"]}},{"`Dot":[{"`Root":"Test"},"Y"]}]},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Y"]}}]}}]},"t"]}},[]]
25-
[{"`Resolved":{"`Type":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_z"]}},"t"]}},[]]
19+
[{"`Resolved":{"`Type":[{"`Canonical":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_z"]}},{"`Resolved":{"`Alias":[{"`Canonical":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_z"]}},{"`Dot":[{"`Root":"Test"},"Z"]}]},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Z"]}}]}}]},"t"]}},[]]
2620

2721
$ odoc_print test.odocl | jq -c ".content.Module.items | .[] | .Module[1].type_.Alias[0] | select(.)"
2822
{"`Resolved":{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"X"]}}]}}]}}
2923
{"`Resolved":{"`Canonical":[{"`Module":[{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"X"]}}]}}]},"M"]},{"`Resolved":{"`Alias":[{"`Module":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},"M"]},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"X_m"]}}]}}]}}
30-
{"`Resolved":{"`Module":[{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"X"]}}]}}]},"N"]}}
24+
{"`Resolved":{"`Canonical":[{"`Module":[{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"X"]}}]}}]},"N"]},{"`Resolved":{"`Alias":[{"`Module":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_x"]}},"N"]},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"X_n"]}}]}}]}}
3125
{"`Resolved":{"`Canonical":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_y"]}},{"`Resolved":{"`Alias":[{"`Canonical":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_y"]}},{"`Dot":[{"`Root":"Test"},"Y"]}]},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Y"]}}]}}]}}
3226
{"`Resolved":{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"W"]}}]}}]}}
3327
{"`Resolved":{"`Canonical":[{"`Module":[{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"W"]}}]}}]},"M"]},{"`Resolved":{"`Alias":[{"`Module":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},"M"]},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"W_m"]}}]}}]}}
34-
{"`Resolved":{"`Module":[{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"W"]}}]}}]},"N"]}}
35-
{"`Resolved":{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_z"]}}}
28+
{"`Resolved":{"`Canonical":[{"`Module":[{"`Canonical":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},{"`Resolved":{"`Alias":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"W"]}}]}}]},"N"]},{"`Resolved":{"`Alias":[{"`Module":[{"`Identifier":{"`Root":[{"`RootPage":"test"},"Test_w"]}},"N"]},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"W_n"]}}]}}]}}
29+
{"`Resolved":{"`Canonical":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_z"]}},{"`Resolved":{"`Alias":[{"`Canonical":[{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Test_z"]}},{"`Dot":[{"`Root":"Test"},"Z"]}]},{"`Identifier":{"`Module":[{"`Root":[{"`RootPage":"test"},"Test"]},"Z"]}}]}}]}}

0 commit comments

Comments
 (0)