diff --git a/.depend b/.depend index 8a2dd0deff0..2d8fb662dc2 100644 --- a/.depend +++ b/.depend @@ -744,6 +744,7 @@ typing/datarepr.cmx : \ parsing/asttypes.cmi \ typing/datarepr.cmi typing/datarepr.cmi : \ + parsing/unit_info.cmi \ typing/types.cmi \ typing/path.cmi \ typing/ident.cmi \ @@ -1449,6 +1450,7 @@ typing/printtyped.cmx : \ typing/printtyped.cmi : \ typing/typedtree.cmi typing/shape.cmo : \ + parsing/unit_info.cmi \ typing/path.cmi \ utils/misc.cmi \ utils/identifiable.cmi \ @@ -1456,6 +1458,7 @@ typing/shape.cmo : \ utils/compilation_unit.cmi \ typing/shape.cmi typing/shape.cmx : \ + parsing/unit_info.cmx \ typing/path.cmx \ utils/misc.cmx \ utils/identifiable.cmx \ @@ -1463,6 +1466,7 @@ typing/shape.cmx : \ utils/compilation_unit.cmx \ typing/shape.cmi typing/shape.cmi : \ + parsing/unit_info.cmi \ typing/path.cmi \ utils/identifiable.cmi \ typing/ident.cmi \ diff --git a/Changes b/Changes index 7e0c9c2fbfd..a9352fea1c3 100644 --- a/Changes +++ b/Changes @@ -661,6 +661,15 @@ OCaml 5.2.0 usages index (Ulysse Gérard, review by Gabriel Scherer and Nathanaëlle Courant) +- #13286: Distinguish unique identifiers `Shape.Uid.t` according to their + provenance: either an implementation or an interface. + (Ulysse Gérard, review by Florian Angeletti and Leo White) + +- #13308: keep track of relations between declaration in the cmt files. This is + useful information for external tools for navigation and analysis purposis. + (Ulysse Gérard, Florian Angeletti, review by Florian Angeletti and Gabriel + Scherer) + ### Build system: - #12198, #12321, #12586, #12616, #12706, #13048: continue the merge of the diff --git a/boot/ocamlc b/boot/ocamlc new file mode 100755 index 00000000000..3fb10ea2e00 Binary files /dev/null and b/boot/ocamlc differ diff --git a/driver/compile_common.ml b/driver/compile_common.ml index 0588b61da4c..eb4a79b180e 100644 --- a/driver/compile_common.ml +++ b/driver/compile_common.ml @@ -86,7 +86,7 @@ let typecheck_intf info ast = Format.(fprintf std_formatter) "%a@." (Printtyp.printed_signature (Unit_info.source_file info.target)) sg); - ignore (Includemod.signatures info.env ~mark:Mark_both + ignore (Includemod.signatures info.env ~mark:true ~modes:(Legacy None) sg sg); Typecore.force_delayed_checks (); Builtin_attributes.warn_unused (); diff --git a/file_formats/cms_format.ml b/file_formats/cms_format.ml index 6b75dc4f401..87b1e9230e3 100644 --- a/file_formats/cms_format.ml +++ b/file_formats/cms_format.ml @@ -17,6 +17,8 @@ (** cms and cmsi files format. *) +module Uid = Shape.Uid + let read_magic_number ic = let len_magic_number = String.length Config.cms_magic_number in really_input_string ic len_magic_number @@ -32,7 +34,9 @@ type cms_infos = { cms_uid_to_attributes : Parsetree.attributes Shape.Uid.Tbl.t; cms_impl_shape : Shape.t option; (* None for mli *) cms_ident_occurrences : - (Longident.t Location.loc * Shape_reduce.result) array + (Longident.t Location.loc * Shape_reduce.result) array; + cms_declaration_dependencies : + (Cmt_format.dependency_kind * Uid.t * Uid.t) list; } type error = @@ -94,7 +98,8 @@ let uid_tables_of_binary_annots binary_annots = ); cms_uid_to_loc, cms_uid_to_attributes -let save_cms target modname binary_annots initial_env shape = +let save_cms target modname binary_annots initial_env shape + cms_declaration_dependencies = if (!Clflags.binary_annotations_cms && not !Clflags.print_types) then begin Misc.output_to_file_via_temporary ~mode:[Open_binary] (Unit_info.Artifact.filename target) @@ -125,7 +130,8 @@ let save_cms target modname binary_annots initial_env shape = cms_uid_to_loc; cms_uid_to_attributes; cms_impl_shape = shape; - cms_ident_occurrences + cms_ident_occurrences; + cms_declaration_dependencies; } in output_cms oc cms) diff --git a/file_formats/cms_format.mli b/file_formats/cms_format.mli index af1dcba9884..c56be6dc0ca 100644 --- a/file_formats/cms_format.mli +++ b/file_formats/cms_format.mli @@ -17,6 +17,8 @@ (** cms and cmsi files format. *) +module Uid = Shape.Uid + type cms_infos = { cms_modname : Compilation_unit.t; cms_comments : (string * Location.t) list; @@ -28,7 +30,9 @@ type cms_infos = { cms_uid_to_attributes : Parsetree.attributes Shape.Uid.Tbl.t; cms_impl_shape : Shape.t option; (* None for mli *) cms_ident_occurrences : - (Longident.t Location.loc * Shape_reduce.result) array + (Longident.t Location.loc * Shape_reduce.result) array; + cms_declaration_dependencies : + (Cmt_format.dependency_kind * Uid.t * Uid.t) list; } type error = @@ -49,6 +53,7 @@ val save_cms : Cmt_format.binary_annots -> Env.t -> (* initial env *) Shape.t option -> + (Cmt_format.dependency_kind * Uid.t * Uid.t) list -> unit val register_toplevel_attributes : diff --git a/file_formats/cmt_format.ml b/file_formats/cmt_format.ml index 2a01bf8d0bb..23805f5b61f 100644 --- a/file_formats/cmt_format.ml +++ b/file_formats/cmt_format.ml @@ -45,11 +45,11 @@ and binary_part = | Partial_signature_item of signature_item | Partial_module_type of module_type +type dependency_kind = Definition_to_declaration | Declaration_to_declaration type cmt_infos = { cmt_modname : Compilation_unit.t; cmt_annots : binary_annots; - cmt_value_dependencies : - (Types.value_description * Types.value_description) list; + cmt_declaration_dependencies : (dependency_kind * Uid.t * Uid.t) list; cmt_comments : (string * Location.t) list; cmt_args : string array; cmt_sourcefile : string option; @@ -453,19 +453,19 @@ let read_cmi filename = | Some cmi, _ -> cmi let saved_types = ref [] -let value_deps = ref [] +let uids_deps : (dependency_kind * Uid.t * Uid.t) list ref = ref [] let clear () = saved_types := []; - value_deps := [] + uids_deps := [] let add_saved_type b = saved_types := b :: !saved_types let get_saved_types () = !saved_types let set_saved_types l = saved_types := l -let record_value_dependency vd1 vd2 = - if vd1.Types.val_loc <> vd2.Types.val_loc then - value_deps := (vd1, vd2) :: !value_deps +let record_declaration_dependency (rk, uid1, uid2) = + if not (Uid.equal uid1 uid2) then + uids_deps := (rk, uid1, uid2) :: !uids_deps let save_cmt target cu binary_annots initial_env cmi shape = if !Clflags.binary_annotations && not !Clflags.print_types then begin @@ -500,7 +500,7 @@ let save_cmt target cu binary_annots initial_env cmi shape = let cmt = { cmt_modname = cu; cmt_annots; - cmt_value_dependencies = !value_deps; + cmt_declaration_dependencies = !uids_deps; cmt_comments = Lexer.comments (); cmt_args = Sys.argv; cmt_sourcefile = sourcefile; @@ -519,3 +519,5 @@ let save_cmt target cu binary_annots initial_env cmi shape = output_cmt oc cmt) end; clear () + +let get_declaration_dependencies () = !uids_deps diff --git a/file_formats/cmt_format.mli b/file_formats/cmt_format.mli index a58d24c6ef2..06e4fbde1fe 100644 --- a/file_formats/cmt_format.mli +++ b/file_formats/cmt_format.mli @@ -48,11 +48,11 @@ and binary_part = | Partial_signature_item of signature_item | Partial_module_type of module_type +type dependency_kind = Definition_to_declaration | Declaration_to_declaration type cmt_infos = { cmt_modname : Compilation_unit.t; cmt_annots : binary_annots; - cmt_value_dependencies : - (Types.value_description * Types.value_description) list; + cmt_declaration_dependencies : (dependency_kind * Uid.t * Uid.t) list; cmt_comments : (string * Location.t) list; cmt_args : string array; cmt_sourcefile : string option; @@ -108,8 +108,7 @@ val add_saved_type : binary_part -> unit val get_saved_types : unit -> binary_part list val set_saved_types : binary_part list -> unit -val record_value_dependency: - Types.value_description -> Types.value_description -> unit +val record_declaration_dependency: dependency_kind * Uid.t * Uid.t -> unit val index_occurrences : binary_annots -> (Longident.t Location.loc * Shape_reduce.result) array @@ -134,3 +133,6 @@ val need_to_clear_env : bool val read_signature : 'a -> string -> Types.signature * 'b list * 'c list *) + +val get_declaration_dependencies : + unit -> (dependency_kind * Uid.t * Uid.t) list diff --git a/middle_end/flambda2/tests/tools/fldiff.ml b/middle_end/flambda2/tests/tools/fldiff.ml index 9dca939ef92..7e2d886a0be 100644 --- a/middle_end/flambda2/tests/tools/fldiff.ml +++ b/middle_end/flambda2/tests/tools/fldiff.ml @@ -9,7 +9,7 @@ let _ = let modname1 = Parse_flambda.make_compilation_unit ~filename:file1 ~extension:".fl" () in - Compilation_unit.set_current (Some modname1); + Compilation_unit.set_current (Some (modname1, Impl)); Format.printf "%a@." (Compare.Comparison.print Flambda_unit.print) (Compare.flambda_units unit1 unit2) diff --git a/middle_end/flambda2/tests/tools/parseflambda.ml b/middle_end/flambda2/tests/tools/parseflambda.ml index 5223e016c70..e6d777c134f 100644 --- a/middle_end/flambda2/tests/tools/parseflambda.ml +++ b/middle_end/flambda2/tests/tools/parseflambda.ml @@ -15,7 +15,7 @@ let parse_flambda filename = let comp_unit = Parse_flambda.make_compilation_unit ~extension:".fl" ~filename () in - Compilation_unit.set_current comp_unit; + Compilation_unit.set_current (Some (comp_unit, Impl)); Format.printf "%a@.@." Print_fexpr.flambda_unit unit; let fl2 = Fexpr_to_flambda.conv comp_unit unit in Format.printf "flambda:@.%a@.@." Flambda_unit.print fl2; diff --git a/testsuite/tests/shape-index/index.reference b/testsuite/tests/shape-index/index.reference index ab08854ebe2..e62b460632b 100644 --- a/testsuite/tests/shape-index/index.reference +++ b/testsuite/tests/shape-index/index.reference @@ -34,30 +34,30 @@ Resolved: Index.3 : t (File "index.ml", line 25, characters 11-12) Resolved: Index.0 : t (File "index.ml", line 20, characters 10-11) Uid of decls: -Index.10: y (File "index.ml", line 40, characters 4-5) -Index.21: MS (File "index.ml", line 51, characters 12-14) -Index.5: A (File "index.ml", line 23, characters 7-8) -Index.15: G (File "index.ml", line 48, characters 7-8) Index.0: t (File "index.ml", line 19, characters 7-8) -Index.28: MSB (File "index.ml", line 65, characters 12-15) -Index.3: t (File "index.ml", line 24, characters 7-8) -Index.17: MT (File "index.ml", line 52, characters 14-16) -Index.11: a (File "index.ml", line 44, characters 4-5) -Index.25: u (File "index.ml", line 66, characters 7-8) -Index.24: MSA (File "index.ml", line 57, characters 12-15) Index.1: x (File "index.ml", line 20, characters 6-7) -Index.16: u (File "index.ml", line 49, characters 5-6) +Index.2: AS (File "index.ml", line 18, characters 12-14) +Index.3: t (File "index.ml", line 24, characters 7-8) +Index.4: x (File "index.ml", line 25, characters 7-8) +Index.5: A (File "index.ml", line 23, characters 7-8) +Index.6: B (File "index.ml", line 28, characters 7-8) +Index.7: c (File "index.ml", line 35, characters 6-7) Index.8: c (File "index.ml", line 32, characters 6-7) Index.9: C (File "index.ml", line 30, characters 7-8) -Index.23: u (File "index.ml", line 60, characters 11-12) -Index.14: F (File "index.ml", line 47, characters 7-8) +Index.10: y (File "index.ml", line 40, characters 4-5) +Index.11: a (File "index.ml", line 44, characters 4-5) Index.12: _ (File "index.ml", line 45, characters 7-8) -Index.27: G (File "index.ml", line 68, characters 9-10) +Index.14: F (File "index.ml", line 47, characters 7-8) +Index.15: G (File "index.ml", line 48, characters 7-8) +Index.16: u (File "index.ml", line 49, characters 5-6) +Index.17: MT (File "index.ml", line 52, characters 14-16) +Index.18: M (File "index.ml", line 53, characters 9-10) +Index.19: X (File "index.ml", line 54, characters 9-10) Index.20: u (File "index.ml", line 55, characters 7-8) +Index.21: MS (File "index.ml", line 51, characters 12-14) +Index.23: u (File "index.ml", line 60, characters 11-12) +Index.24: MSA (File "index.ml", line 57, characters 12-15) +Index.25: u (File "index.ml", line 66, characters 7-8) Index.26: t (File "index.ml", line 67, characters 23-24) -Index.19: X (File "index.ml", line 54, characters 9-10) -Index.6: B (File "index.ml", line 28, characters 7-8) -Index.4: x (File "index.ml", line 25, characters 7-8) -Index.18: M (File "index.ml", line 53, characters 9-10) -Index.7: c (File "index.ml", line 35, characters 6-7) -Index.2: AS (File "index.ml", line 18, characters 12-14) +Index.27: G (File "index.ml", line 68, characters 9-10) +Index.28: MSB (File "index.ml", line 65, characters 12-15) diff --git a/testsuite/tests/shape-index/index_aliases.reference b/testsuite/tests/shape-index/index_aliases.reference index e433d55b2a8..ca456ec6fb1 100644 --- a/testsuite/tests/shape-index/index_aliases.reference +++ b/testsuite/tests/shape-index/index_aliases.reference @@ -38,29 +38,29 @@ Resolved: Index_aliases.1 : A (File "index_aliases.ml", line 19, characters 11-12) Uid of decls: -Index_aliases.12: M (File "index_aliases.ml", line 32, characters 9-10) +Index_aliases.0: t (File "index_aliases.ml", line 18, characters 23-24) Index_aliases.1: A (File "index_aliases.ml", line 18, characters 7-8) Index_aliases.2: B (File "index_aliases.ml", line 19, characters 7-8) -Index_aliases.18: s (File "index_aliases.ml", line 36, characters 26-27) -Index_aliases.17: x (File "index_aliases.ml", line 35, characters 4-5) +Index_aliases.3: t (File "index_aliases.ml", line 21, characters 23-24) Index_aliases.5: F (File "index_aliases.ml", line 21, characters 7-8) -Index_aliases.26: FArg (File "index_aliases.ml", line 48, characters 7-11) +Index_aliases.6: F' (File "index_aliases.ml", line 22, characters 7-9) Index_aliases.7: C (File "index_aliases.ml", line 23, characters 7-8) -Index_aliases.24: Z (File "index_aliases.ml", line 42, characters 7-8) -Index_aliases.20: t (File "index_aliases.ml", line 37, characters 41-42) +Index_aliases.8: C' (File "index_aliases.ml", line 25, characters 7-9) Index_aliases.9: D (File "index_aliases.ml", line 26, characters 7-8) +Index_aliases.10: G (File "index_aliases.ml", line 28, characters 7-8) +Index_aliases.11: s (File "index_aliases.ml", line 32, characters 21-22) +Index_aliases.12: M (File "index_aliases.ml", line 32, characters 9-10) +Index_aliases.14: t (File "index_aliases.ml", line 33, characters 48-49) Index_aliases.15: F (File "index_aliases.ml", line 33, characters 9-10) +Index_aliases.16: S (File "index_aliases.ml", line 31, characters 12-13) +Index_aliases.17: x (File "index_aliases.ml", line 35, characters 4-5) +Index_aliases.18: s (File "index_aliases.ml", line 36, characters 26-27) Index_aliases.19: M (File "index_aliases.ml", line 36, characters 11-12) -Index_aliases.8: C' (File "index_aliases.ml", line 25, characters 7-9) -Index_aliases.23: Y (File "index_aliases.ml", line 41, characters 7-8) -Index_aliases.14: t (File "index_aliases.ml", line 33, characters 48-49) -Index_aliases.10: G (File "index_aliases.ml", line 28, characters 7-8) -Index_aliases.27: u (File "index_aliases.ml", line 52, characters 5-6) +Index_aliases.20: t (File "index_aliases.ml", line 37, characters 41-42) +Index_aliases.21: F (File "index_aliases.ml", line 37, characters 11-12) Index_aliases.22: X (File "index_aliases.ml", line 40, characters 7-8) -Index_aliases.16: S (File "index_aliases.ml", line 31, characters 12-13) +Index_aliases.23: Y (File "index_aliases.ml", line 41, characters 7-8) +Index_aliases.24: Z (File "index_aliases.ml", line 42, characters 7-8) Index_aliases.25: Arg (File "index_aliases.ml", line 47, characters 7-10) -Index_aliases.21: F (File "index_aliases.ml", line 37, characters 11-12) -Index_aliases.6: F' (File "index_aliases.ml", line 22, characters 7-9) -Index_aliases.3: t (File "index_aliases.ml", line 21, characters 23-24) -Index_aliases.11: s (File "index_aliases.ml", line 32, characters 21-22) -Index_aliases.0: t (File "index_aliases.ml", line 18, characters 23-24) +Index_aliases.26: FArg (File "index_aliases.ml", line 48, characters 7-11) +Index_aliases.27: u (File "index_aliases.ml", line 52, characters 5-6) diff --git a/testsuite/tests/shape-index/index_bindingops.reference b/testsuite/tests/shape-index/index_bindingops.reference index 38c4f70b4d1..8892fd4ecf8 100644 --- a/testsuite/tests/shape-index/index_bindingops.reference +++ b/testsuite/tests/shape-index/index_bindingops.reference @@ -39,9 +39,9 @@ Unresolved: CU Stdlib . "Option"[module] . "map"[value] : Option.map (File "index_bindingops.ml", line 17, characters 17-27) Uid of decls: -Index_bindingops.8: - minus_three (File "index_bindingops.ml", line 23, characters 4-15) Index_bindingops.0: let+ (File "index_bindingops.ml", line 17, characters 4-10) Index_bindingops.3: and+ (File "index_bindingops.ml", line 19, characters 4-10) +Index_bindingops.8: + minus_three (File "index_bindingops.ml", line 23, characters 4-15) diff --git a/testsuite/tests/shape-index/index_constrs.reference b/testsuite/tests/shape-index/index_constrs.reference index 3fe533e8b6b..c8cec480385 100644 --- a/testsuite/tests/shape-index/index_constrs.reference +++ b/testsuite/tests/shape-index/index_constrs.reference @@ -17,10 +17,10 @@ Resolved: Index_constrs.0 : E (File "index_constrs.ml", line 20, characters 16-17) Uid of decls: -Index_constrs.6: f (File "index_constrs.ml", line 27, characters 4-5) -Index_constrs.5: x_ (File "index_constrs.ml", line 25, characters 4-6) Index_constrs.0: E (File "index_constrs.ml", line 18, characters 10-11) -Index_constrs.2: M (File "index_constrs.ml", line 19, characters 7-8) Index_constrs.1: F (File "index_constrs.ml", line 20, characters 12-13) +Index_constrs.2: M (File "index_constrs.ml", line 19, characters 7-8) Index_constrs.3: t (File "index_constrs.ml", line 23, characters 5-6) Index_constrs.4: E (File "index_constrs.ml", line 23, characters 9-10) +Index_constrs.5: x_ (File "index_constrs.ml", line 25, characters 4-6) +Index_constrs.6: f (File "index_constrs.ml", line 27, characters 4-5) diff --git a/testsuite/tests/shape-index/index_constrs_records.reference b/testsuite/tests/shape-index/index_constrs_records.reference index e876416599e..e4a6f808fb4 100644 --- a/testsuite/tests/shape-index/index_constrs_records.reference +++ b/testsuite/tests/shape-index/index_constrs_records.reference @@ -57,37 +57,37 @@ Resolved: Index_constrs_records.4 : A (File "index_constrs_records.ml", line 22, characters 10-11) Uid of decls: -Index_constrs_records.4: - A (File "index_constrs_records.ml", line 21, characters 11-12) -Index_constrs_records.12: - l_c (File "index_constrs_records.ml", line 19, characters 18-21) +Index_constrs_records.0: + l (File "index_constrs_records.ml", line 17, characters 5-6) +Index_constrs_records.1: + lbl (File "index_constrs_records.ml", line 17, characters 11-14) Index_constrs_records.2: t (File "index_constrs_records.ml", line 21, characters 7-8) -Index_constrs_records.34: - l_exn (File "index_constrs_records.ml", line 39, characters 18-23) -Index_constrs_records.29: - Ext (File "index_constrs_records.ml", line 33, characters 10-13) Index_constrs_records.3: l_c (File "index_constrs_records.ml", line 21, characters 18-21) -Index_constrs_records.21: - M (File "index_constrs_records.ml", line 18, characters 7-8) -Index_constrs_records.35: - Exn (File "index_constrs_records.ml", line 39, characters 10-13) -Index_constrs_records.13: - A (File "index_constrs_records.ml", line 19, characters 11-12) -Index_constrs_records.37: - e (File "index_constrs_records.ml", line 41, characters 4-5) -Index_constrs_records.31: - f (File "index_constrs_records.ml", line 35, characters 4-5) +Index_constrs_records.4: + A (File "index_constrs_records.ml", line 21, characters 11-12) Index_constrs_records.11: t (File "index_constrs_records.ml", line 19, characters 7-8) +Index_constrs_records.12: + l_c (File "index_constrs_records.ml", line 19, characters 18-21) +Index_constrs_records.13: + A (File "index_constrs_records.ml", line 19, characters 11-12) +Index_constrs_records.21: + M (File "index_constrs_records.ml", line 18, characters 7-8) +Index_constrs_records.23: + f (File "index_constrs_records.ml", line 30, characters 4-5) Index_constrs_records.27: u (File "index_constrs_records.ml", line 32, characters 5-6) Index_constrs_records.28: l_ext (File "index_constrs_records.ml", line 33, characters 19-24) -Index_constrs_records.0: - l (File "index_constrs_records.ml", line 17, characters 5-6) -Index_constrs_records.23: - f (File "index_constrs_records.ml", line 30, characters 4-5) -Index_constrs_records.1: - lbl (File "index_constrs_records.ml", line 17, characters 11-14) +Index_constrs_records.29: + Ext (File "index_constrs_records.ml", line 33, characters 10-13) +Index_constrs_records.31: + f (File "index_constrs_records.ml", line 35, characters 4-5) +Index_constrs_records.34: + l_exn (File "index_constrs_records.ml", line 39, characters 18-23) +Index_constrs_records.35: + Exn (File "index_constrs_records.ml", line 39, characters 10-13) +Index_constrs_records.37: + e (File "index_constrs_records.ml", line 41, characters 4-5) diff --git a/testsuite/tests/shape-index/index_functor.reference b/testsuite/tests/shape-index/index_functor.reference index 89867f0bafe..04746c8d555 100644 --- a/testsuite/tests/shape-index/index_functor.reference +++ b/testsuite/tests/shape-index/index_functor.reference @@ -11,7 +11,7 @@ Resolved: Index_functor.0 : X (File "index_functor.ml", line 18, characters 43-44) Uid of decls: +Index_functor.1: M (File "index_functor.ml", line 18, characters 39-40) +Index_functor.2: F (File "index_functor.ml", line 18, characters 7-8) Index_functor.3: N (File "index_functor.ml", line 19, characters 7-8) Index_functor.4: O (File "index_functor.ml", line 20, characters 7-8) -Index_functor.2: F (File "index_functor.ml", line 18, characters 7-8) -Index_functor.1: M (File "index_functor.ml", line 18, characters 39-40) diff --git a/testsuite/tests/shape-index/index_labels.reference b/testsuite/tests/shape-index/index_labels.reference index 797744dfe31..ae84539a8ef 100644 --- a/testsuite/tests/shape-index/index_labels.reference +++ b/testsuite/tests/shape-index/index_labels.reference @@ -17,9 +17,9 @@ Resolved: Index_labels.1 : a (File "index_labels.ml", line 20, characters 10-11) Uid of decls: -Index_labels.5: f (File "index_labels.ml", line 25, characters 4-5) +Index_labels.0: t (File "index_labels.ml", line 18, characters 5-6) +Index_labels.1: a (File "index_labels.ml", line 18, characters 19-20) Index_labels.2: b (File "index_labels.ml", line 18, characters 27-28) Index_labels.3: x (File "index_labels.ml", line 20, characters 4-5) -Index_labels.1: a (File "index_labels.ml", line 18, characters 19-20) Index_labels.4: _y (File "index_labels.ml", line 21, characters 4-6) -Index_labels.0: t (File "index_labels.ml", line 18, characters 5-6) +Index_labels.5: f (File "index_labels.ml", line 25, characters 4-5) diff --git a/testsuite/tests/shape-index/index_objects.reference b/testsuite/tests/shape-index/index_objects.reference index 1a0b3a3ab25..4d44a656558 100644 --- a/testsuite/tests/shape-index/index_objects.reference +++ b/testsuite/tests/shape-index/index_objects.reference @@ -23,10 +23,10 @@ Resolved: Index_objects.0 : o (File "index_objects.ml", line 23, characters 9-10) Uid of decls: +Index_objects.0: o (File "index_objects.ml", line 18, characters 4-5) +Index_objects.5: c (File "index_objects.ml", line 25, characters 6-7) Index_objects.10: d (File "index_objects.ml", line 31, characters 6-7) -Index_objects.15: M (File "index_objects.ml", line 35, characters 12-13) +Index_objects.13: ct (File "index_objects.ml", line 36, characters 8-10) Index_objects.14: dt (File "index_objects.ml", line 40, characters 8-10) -Index_objects.5: c (File "index_objects.ml", line 25, characters 6-7) -Index_objects.0: o (File "index_objects.ml", line 18, characters 4-5) +Index_objects.15: M (File "index_objects.ml", line 35, characters 12-13) Index_objects.16: ins_var (File "index_objects.ml", line 43, characters 6-13) -Index_objects.13: ct (File "index_objects.ml", line 36, characters 8-10) diff --git a/testsuite/tests/shape-index/index_types.reference b/testsuite/tests/shape-index/index_types.reference index 330c8e29244..b7887fa3be3 100644 --- a/testsuite/tests/shape-index/index_types.reference +++ b/testsuite/tests/shape-index/index_types.reference @@ -12,15 +12,15 @@ Resolved: Index_types.0 : t (File "index_types.ml", line 20, characters 8-9) Resolved: Index_types.0 : t (File "index_types.ml", line 20, characters 8-9) Uid of decls: -Index_types.11: u (File "index_types.ml", line 41, characters 5-6) -Index_types.3: poly (File "index_types.ml", line 27, characters 5-9) +Index_types.0: t (File "index_types.ml", line 18, characters 5-6) +Index_types.1: x (File "index_types.ml", line 20, characters 4-5) Index_types.2: M (File "index_types.ml", line 22, characters 7-8) -Index_types.6: S (File "index_types.ml", line 31, characters 12-13) -Index_types.10: N (File "index_types.ml", line 40, characters 7-8) -Index_types.5: B (File "index_types.ml", line 33, characters 13-14) -Index_types.9: t (File "index_types.ml", line 40, characters 23-24) +Index_types.3: poly (File "index_types.ml", line 27, characters 5-9) Index_types.4: t2 (File "index_types.ml", line 32, characters 7-9) -Index_types.1: x (File "index_types.ml", line 20, characters 4-5) -Index_types.8: B (File "index_types.ml", line 37, characters 11-12) -Index_types.0: t (File "index_types.ml", line 18, characters 5-6) +Index_types.5: B (File "index_types.ml", line 33, characters 13-14) +Index_types.6: S (File "index_types.ml", line 31, characters 12-13) Index_types.7: t1 (File "index_types.ml", line 36, characters 5-7) +Index_types.8: B (File "index_types.ml", line 37, characters 11-12) +Index_types.9: t (File "index_types.ml", line 40, characters 23-24) +Index_types.10: N (File "index_types.ml", line 40, characters 7-8) +Index_types.11: u (File "index_types.ml", line 41, characters 5-6) diff --git a/testsuite/tests/shape-index/index_unboxed_labels.reference b/testsuite/tests/shape-index/index_unboxed_labels.reference index ad75879c736..701e06820b1 100644 --- a/testsuite/tests/shape-index/index_unboxed_labels.reference +++ b/testsuite/tests/shape-index/index_unboxed_labels.reference @@ -29,35 +29,35 @@ Resolved: Index_unboxed_labels.1 : a (File "index_unboxed_labels.ml", line 21, characters 10-11) Uid of decls: -Index_unboxed_labels.2: - b (File "index_unboxed_labels.ml", line 18, characters 19-20) -Index_unboxed_labels.16: - f (File "index_unboxed_labels.ml", line 40, characters 4-5) -Index_unboxed_labels.7: - f (File "index_unboxed_labels.ml", line 24, characters 4-5) +Index_unboxed_labels.0: + t (File "index_unboxed_labels.ml", line 18, characters 5-6) Index_unboxed_labels.1: a (File "index_unboxed_labels.ml", line 18, characters 11-12) -Index_unboxed_labels.13: - b (File "index_unboxed_labels.ml", line 35, characters 12-13) -Index_unboxed_labels.6: - _y (File "index_unboxed_labels.ml", line 22, characters 4-6) -Index_unboxed_labels.4: - a (File "index_unboxed_labels.ml", line 19, characters 13-14) +Index_unboxed_labels.2: + b (File "index_unboxed_labels.ml", line 18, characters 19-20) Index_unboxed_labels.3: tu (File "index_unboxed_labels.ml", line 19, characters 5-7) -Index_unboxed_labels.11: - f (File "index_unboxed_labels.ml", line 31, characters 4-5) +Index_unboxed_labels.4: + a (File "index_unboxed_labels.ml", line 19, characters 13-14) Index_unboxed_labels.5: x (File "index_unboxed_labels.ml", line 21, characters 4-5) +Index_unboxed_labels.6: + _y (File "index_unboxed_labels.ml", line 22, characters 4-6) +Index_unboxed_labels.7: + f (File "index_unboxed_labels.ml", line 24, characters 4-5) +Index_unboxed_labels.9: + x (File "index_unboxed_labels.ml", line 28, characters 4-5) +Index_unboxed_labels.10: + _y (File "index_unboxed_labels.ml", line 29, characters 4-6) +Index_unboxed_labels.11: + f (File "index_unboxed_labels.ml", line 31, characters 4-5) +Index_unboxed_labels.12: + tb (File "index_unboxed_labels.ml", line 35, characters 5-7) +Index_unboxed_labels.13: + b (File "index_unboxed_labels.ml", line 35, characters 12-13) Index_unboxed_labels.14: x (File "index_unboxed_labels.ml", line 37, characters 4-5) Index_unboxed_labels.15: _y (File "index_unboxed_labels.ml", line 38, characters 4-6) -Index_unboxed_labels.12: - tb (File "index_unboxed_labels.ml", line 35, characters 5-7) -Index_unboxed_labels.0: - t (File "index_unboxed_labels.ml", line 18, characters 5-6) -Index_unboxed_labels.10: - _y (File "index_unboxed_labels.ml", line 29, characters 4-6) -Index_unboxed_labels.9: - x (File "index_unboxed_labels.ml", line 28, characters 4-5) +Index_unboxed_labels.16: + f (File "index_unboxed_labels.ml", line 40, characters 4-5) diff --git a/testsuite/tests/shape-index/index_vb.reference b/testsuite/tests/shape-index/index_vb.reference index a48f72fff64..cb96c56c3d4 100644 --- a/testsuite/tests/shape-index/index_vb.reference +++ b/testsuite/tests/shape-index/index_vb.reference @@ -16,9 +16,9 @@ Resolved: Index_vb.2 : b (File "index_vb.ml", line 20, characters 9-10) Resolved: Index_vb.1 : a (File "index_vb.ml", line 20, characters 6-7) Uid of decls: -Index_vb.3: a (File "index_vb.ml", line 20, characters 6-7) -Index_vb.1: a (File "index_vb.ml", line 18, characters 11-12) Index_vb.0: t (File "index_vb.ml", line 18, characters 5-6) +Index_vb.1: a (File "index_vb.ml", line 18, characters 11-12) Index_vb.2: b (File "index_vb.ml", line 18, characters 20-21) -Index_vb.5: a (File "index_vb.ml", line 20, characters 6-7) +Index_vb.3: a (File "index_vb.ml", line 20, characters 6-7) Index_vb.4: a (File "index_vb.ml", line 20, characters 6-7) +Index_vb.5: a (File "index_vb.ml", line 20, characters 6-7) diff --git a/testsuite/tests/uid-deps/link_intf_impl.ml b/testsuite/tests/uid-deps/link_intf_impl.ml new file mode 100644 index 00000000000..6d2090a1313 --- /dev/null +++ b/testsuite/tests/uid-deps/link_intf_impl.ml @@ -0,0 +1,59 @@ +(* TEST + +flags = "-bin-annot -bin-annot-occurrences"; +compile_only = "true"; +setup-ocamlc.byte-build-env; +all_modules = "link_intf_impl.mli link_intf_impl.ml"; +ocamlc.byte; +check-ocamlc.byte-output; + +program = "-quiet -uid-deps link_intf_impl.cmt"; +output = "out_objinfo"; +ocamlobjinfo; + +check-program-output; +*) + +let x (* 0 *) = 42 + +type t (* 1 *) = int + +module type S (* 3 *) = sig + val y (* 2 *) : t +end + +module M (* 5 *) : S = struct + let y (* 4 *) = 36 +end + +module N (* 8 *) : sig + val y (* 7 *) : int +end = struct + let y (* 6 *) = 2 +end + +let _ = (module N : S) + +module P (* 10 *)= struct + let y (* 9 *) = 12 +end + +module F (* 12 *) (X (* 11 *) : S) = X + +module G (* 13 *) = F(P) + +module type Initial (* 16 *) = sig + module type Nested (* 15 *) = sig + type t (* 14 *) + end +end + +module MF (* 23 *) : sig + module F (* 22 *) (X (* 21 *) : sig val x (* 20 *) : int end) : sig end +end = struct + module F (* 19 *) (X (* 18 *) : sig val x (* 17 *) : int end) = struct end +end + +module FMT (* 27 *) (X (* 26 *) : sig + module type MT (* 25 *) = sig val x (* 24 *) : int end +end) : sig end = struct end diff --git a/testsuite/tests/uid-deps/link_intf_impl.mli b/testsuite/tests/uid-deps/link_intf_impl.mli new file mode 100644 index 00000000000..fa4403c9c10 --- /dev/null +++ b/testsuite/tests/uid-deps/link_intf_impl.mli @@ -0,0 +1,19 @@ +type t (* 0 *) + +val x (* 1 *) : t + +module type S (* 3 *) = sig + val y (* 2 *) : t +end + +module M (* 4 *) : S + +module type Initial (* 7 *) = sig + module type Nested (* 6 *) = sig + type t (* 5 *) + end +end + +module FMT (* 11 *) (X (* 10 *) : sig + module type MT (* 9 *) = sig val x (* 8 *) : int end +end) : sig end diff --git a/testsuite/tests/uid-deps/link_intf_impl.reference b/testsuite/tests/uid-deps/link_intf_impl.reference new file mode 100644 index 00000000000..3e6ffa226ad --- /dev/null +++ b/testsuite/tests/uid-deps/link_intf_impl.reference @@ -0,0 +1,19 @@ + +Uid dependencies: +Link_intf_impl.0 <- [intf]Link_intf_impl.1 +Link_intf_impl.1 <- [intf]Link_intf_impl.0 +Link_intf_impl.2 <-> [intf]Link_intf_impl.2 +Link_intf_impl.3 <- [intf]Link_intf_impl.3 +Link_intf_impl.4 <- Link_intf_impl.2 +Link_intf_impl.5 <- [intf]Link_intf_impl.4 +Link_intf_impl.6 <- Link_intf_impl.7 +Link_intf_impl.7 <-> Link_intf_impl.2 +Link_intf_impl.9 <-> Link_intf_impl.2 +Link_intf_impl.14 <-> [intf]Link_intf_impl.5 +Link_intf_impl.15 <-> [intf]Link_intf_impl.6 +Link_intf_impl.16 <- [intf]Link_intf_impl.7 +Link_intf_impl.17 <-> Link_intf_impl.20 +Link_intf_impl.19 <- Link_intf_impl.22 +Link_intf_impl.24 <-> [intf]Link_intf_impl.8 +Link_intf_impl.25 <-> [intf]Link_intf_impl.9 +Link_intf_impl.27 <- [intf]Link_intf_impl.11 diff --git a/testsuite/tests/uids/intf_uids.ml b/testsuite/tests/uids/intf_uids.ml new file mode 100644 index 00000000000..af315bf6033 --- /dev/null +++ b/testsuite/tests/uids/intf_uids.ml @@ -0,0 +1,3 @@ +type u (* has uid Intf_uids.0 *) + +type t (* has uid Intf_uids.1 *) diff --git a/testsuite/tests/uids/intf_uids.mli b/testsuite/tests/uids/intf_uids.mli new file mode 100644 index 00000000000..21cfde35a94 --- /dev/null +++ b/testsuite/tests/uids/intf_uids.mli @@ -0,0 +1,3 @@ +type t (* has uid [intf]Intf_uids.0 *) + +type u (* has uid [intf]Intf_uids.1 *) diff --git a/testsuite/tests/uids/intf_uids_test.ml b/testsuite/tests/uids/intf_uids_test.ml new file mode 100644 index 00000000000..a5faf8e2c99 --- /dev/null +++ b/testsuite/tests/uids/intf_uids_test.ml @@ -0,0 +1,22 @@ +(* TEST + +flags = "-bin-annot"; +compile_only = "true"; +modules = "intf_uids.ml"; + +setup-ocamlc.byte-build-env; +all_modules = "intf_uids.mli intf_uids.ml"; +ocamlc.byte; +check-ocamlc.byte-output; + +program = "-quiet -decls intf_uids.cmti intf_uids.cmt"; +output = "out_objinfo"; +ocamlobjinfo; + +check-program-output; +*) + +(* This test illustrates the fact that uids are tagged to indicate if they + originate from an interface of an implementation: it prints the delcarations + written in the cmt file for the interface and then for the implementation. + These should not overlap. *) diff --git a/testsuite/tests/uids/intf_uids_test.reference b/testsuite/tests/uids/intf_uids_test.reference new file mode 100644 index 00000000000..a1963210cec --- /dev/null +++ b/testsuite/tests/uids/intf_uids_test.reference @@ -0,0 +1,8 @@ + +Uid of decls: +[intf]Intf_uids.0: t (File "intf_uids.mli", line 1, characters 5-6) +[intf]Intf_uids.1: u (File "intf_uids.mli", line 3, characters 5-6) + +Uid of decls: +Intf_uids.0: u (File "intf_uids.ml", line 1, characters 5-6) +Intf_uids.1: t (File "intf_uids.ml", line 3, characters 5-6) diff --git a/testsuite/tests/warnings/w32.compilers.reference b/testsuite/tests/warnings/w32.compilers.reference index 87d8f50cbf9..005a846ff52 100644 --- a/testsuite/tests/warnings/w32.compilers.reference +++ b/testsuite/tests/warnings/w32.compilers.reference @@ -103,3 +103,34 @@ File "w32.ml", line 76, characters 29-40: 76 | module type S = sig type t val x : int end ^^^^^^^^^^^ Warning 32 [unused-value-declaration]: unused value x. + +File "w32.ml", line 87, characters 2-49: +87 | module F (_ : sig val test : int end) : sig end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 60 [unused-module]: unused module F. + +File "w32.ml", lines 86-90, characters 0-3: +86 | module I : sig +87 | module F (_ : sig val test : int end) : sig end +88 | end = struct +89 | module F (X: sig val test : int end) = struct let _ = X.test end +90 | end +Warning 60 [unused-module]: unused module I. + +File "w32.ml", lines 94-98, characters 0-3: +94 | module rec X: sig +95 | module F(_:sig val x:int end): sig end +96 | end = struct +97 | module F(X:sig val x:int end) = struct let _ = X.x end +98 | end +Warning 60 [unused-module]: unused module X. + +File "w32.ml", line 99, characters 0-27: +99 | and Y: sig end = struct end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 60 [unused-module]: unused module Y. + +File "w32.ml", line 95, characters 2-40: +95 | module F(_:sig val x:int end): sig end + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Warning 60 [unused-module]: unused module F. diff --git a/testsuite/tests/warnings/w32.ml b/testsuite/tests/warnings/w32.ml index 520ec3de6d9..f1e01b53f72 100644 --- a/testsuite/tests/warnings/w32.ml +++ b/testsuite/tests/warnings/w32.ml @@ -81,6 +81,23 @@ module Nominal = struct module N = F(M) end +(* from ocaml/ocaml#13955 no unused warning should be triggered for [test] *) + +module I : sig + module F (_ : sig val test : int end) : sig end +end = struct + module F (X: sig val test : int end) = struct let _ = X.test end +end + +(* same for the recursive version *) + +module rec X: sig + module F(_:sig val x:int end): sig end +end = struct + module F(X:sig val x:int end) = struct let _ = X.x end +end +and Y: sig end = struct end + (* TEST flags = "-w +A"; setup-ocamlc.byte-build-env; diff --git a/tools/objinfo.ml b/tools/objinfo.ml index 24952f8d264..30894f2bbf1 100644 --- a/tools/objinfo.ml +++ b/tools/objinfo.ml @@ -39,6 +39,7 @@ let no_crc = ref false let shape = ref false let index = ref false let decls = ref false +let uid_deps = ref false module Magic_number = Misc.Magic_number module String = Misc.Stdlib.String @@ -214,9 +215,32 @@ let print_cmt_infos cmt = cmt.cmt_ident_occurrences; Format.print_flush () end; + if !uid_deps then begin + printf "\nUid dependencies:\n"; + let arr = Array.of_list cmt.cmt_declaration_dependencies in + let () = + Array.sort (fun (_tr, u1, u2) (_tr', u1', u2') -> + match Shape.Uid.compare u1 u1' with + | 0 -> Shape.Uid.compare u2 u2' + | n -> n) arr + in + Format.printf "@["; + Array.iter (fun (rk, u1, u2) -> + let rk = match rk with + | Definition_to_declaration -> "<-" + | Declaration_to_declaration -> "<->" + in + Format.printf "@[%a %s %a@]@;" + Shape.Uid.print u1 + rk + Shape.Uid.print u2) arr; + Format.printf "@]"; + end; if !decls then begin printf "\nUid of decls:\n"; - Shape.Uid.Tbl.iter (fun uid item -> + let decls = Array.of_list (Shape.Uid.Tbl.to_list cmt.cmt_uid_to_decl) in + Array.sort (fun (uid, _) (uid', _) -> Shape.Uid.compare uid uid') decls; + Array.iter (fun (uid, item) -> let loc = match (item : Typedtree.item_declaration) with | Value vd -> vd.val_name | Value_binding vb -> @@ -246,8 +270,8 @@ let print_cmt_infos cmt = Format.printf "@[%a:@ %a@]@;" Shape.Uid.print uid pp_loc loc) - cmt.cmt_uid_to_decl; - Format.print_flush () + decls; + Format.print_flush () end let print_cms_infos cms = @@ -570,6 +594,8 @@ let arg_list = [ " Print a list of all usages of values, types, etc. in the module"; "-decls", Arg.Set decls, " Print a list of all declarations in the module"; + "-uid-deps", Arg.Set uid_deps, + " Print the declarations' uids dependencies of the module"; "-null-crc", Arg.Set no_crc, " Print a null CRC for imported interfaces"; "-args", Arg.Expand Arg.read_arg, " Read additional newline separated command line arguments \n\ diff --git a/toplevel/byte/topeval.ml b/toplevel/byte/topeval.ml index 47ccbef1c7a..c690b70a887 100644 --- a/toplevel/byte/topeval.ml +++ b/toplevel/byte/topeval.ml @@ -127,8 +127,7 @@ let execute_phrase print_outcome ppf phr = in if !Clflags.dump_typedtree then Printtyped.implementation ppf str; let sg' = Typemod.Signature_names.simplify newenv sn sg in - ignore (Includemod.signatures ~mark:Mark_positive oldenv - ~modes:(Legacy None) sg sg'); + Includemod.check_implementation oldenv ~modes:(Legacy None) sg sg'; Typecore.force_delayed_checks (); let shape = Shape_reduce.local_reduce Env.empty shape in if !Clflags.dump_shape then Shape.print ppf shape; diff --git a/toplevel/native/opttoploop.ml b/toplevel/native/opttoploop.ml index 0c6344400c9..670d124ed8b 100644 --- a/toplevel/native/opttoploop.ml +++ b/toplevel/native/opttoploop.ml @@ -404,7 +404,7 @@ let execute_phrase print_outcome ppf phr = if !Clflags.dump_typedtree then Printtyped.implementation ppf str; let sg' = Typemod.Signature_names.simplify newenv names sg in let coercion = - Includemod.signatures oldenv ~mark:Mark_positive + Includemod.signatures oldenv ~mark:true ~modes:(Legacy None) sg sg' in Typecore.force_delayed_checks (); diff --git a/toplevel/native/topeval.ml b/toplevel/native/topeval.ml index 22b6a9c2475..fdfb4a1cc1e 100644 --- a/toplevel/native/topeval.ml +++ b/toplevel/native/topeval.ml @@ -185,7 +185,7 @@ let execute_phrase print_outcome ppf phr = in if !Clflags.dump_typedtree then Printtyped.implementation ppf str; let sg' = Typemod.Signature_names.simplify newenv names sg in - ignore (Includemod.signatures oldenv ~mark:Mark_positive sg sg'); + Includemod.check_implementation oldenv ~modes:(Legacy None) sg sg'; Typecore.force_delayed_checks (); let shape = Shape_reduce.local_reduce Env.empty shape in if !Clflags.dump_shape then Shape.print ppf shape; diff --git a/typing/includemod.ml b/typing/includemod.ml index e097fbc8245..fd5d8f062a4 100644 --- a/typing/includemod.ml +++ b/typing/includemod.ml @@ -120,21 +120,93 @@ module Error = struct end -type mark = +module Directionality = struct + + + type mark = | Mark_both | Mark_positive - | Mark_negative | Mark_neither -let negate_mark = function - | Mark_both -> Mark_both - | Mark_positive -> Mark_negative - | Mark_negative -> Mark_positive - | Mark_neither -> Mark_neither + type pos = + | Strictly_positive + (** Strictly positive positions are notable for tools since they are the + the case where we match a implementation definition with an interface + declaration. Oherwise in the positive case we are matching + declatations inside functor arguments at even level of nesting.*) + | Positive + | Negative -let mark_positive = function - | Mark_both | Mark_positive -> true - | Mark_negative | Mark_neither -> false + +(** + When checking inclusion, the [Directionality.t] type tracks the + subtyping direction at the syntactic level. + + The [posivity] field is used in the [cmt_declaration_dependencies] to + distinguish between directed and undirected edges, and to avoid recording + matched declarations twice. + + The [mark_as_used] field describes if we should record only positive use, + any use (because there is no clear implementation side), or none (because we + are inside an auxiliary check function.) + + The [in_eq] field is [true] when we are checking both directions inside of + module types which allows optimizing module type equality checks. The module + subtyping relation [A <: B] checks that [A.T = B.T] when [A] and [B] define a + module type [T]. The relation [A.T = B.T] is equivalent to [(A.T <: B.T) and + (B.T <: A.T)], but checking both recursively would lead to an exponential + slowdown (see #10598 and #10616). To avoid this issue, when [in_eq] is + [true], we compute a coarser relation [A << B] which is the same as [A <: B] + except that module types [T] are checked only for [A.T << B.T] and not the + reverse. Thus, we can implement a cheap module type equality check [A.T = + B.T] by computing [(A.T << B.T) and (B.T << A.T)], avoiding the exponential + slowdown described above. +*) + type t = { + in_eq:bool; + mark_as_used:mark; + pos:pos; + } + + let strictly_positive ~mark ~both = + let mark_as_used = + match mark, both with + | true, true -> Mark_both + | true, false -> Mark_positive + | false, _ -> Mark_neither + in + { in_eq=false; pos=Strictly_positive; mark_as_used } + + let unknown ~mark = + let mark_as_used = if mark then Mark_both else Mark_neither in + { in_eq=false; pos=Positive; mark_as_used } + + let negate_pos = function + | Positive | Strictly_positive -> Negative + | Negative -> Positive + + let negate d = { d with pos = negate_pos d.pos } + + let at_most_positive = function + | Strictly_positive -> Positive + | Positive | Negative as non_strict -> non_strict + + let enter_eq d = + { + in_eq = true; + pos = at_most_positive d.pos; + mark_as_used = d.mark_as_used + } + + let mark_as_used d = match d.mark_as_used with + | Mark_neither -> false + | Mark_both -> true + | Mark_positive -> + match d.pos with + | Positive | Strictly_positive -> true + | Negative -> false + +end (* All functions "blah env x1 x2" check that x1 is included in x2, i.e. that x1 is the type of an implementation that fulfills the @@ -153,9 +225,8 @@ let append_ldot s = function (* Inclusion between value descriptions *) -let value_descriptions ~loc env ~mark subst id ~mmodes vd1 vd2 = - Cmt_format.record_value_dependency vd1 vd2; - if mark_positive mark then +let value_descriptions ~loc env ~direction subst id ~mmodes vd1 vd2 = + if Directionality.mark_as_used direction then Env.mark_value_used vd1.val_uid; let vd2 = Subst.value_description subst vd2 in try @@ -165,8 +236,8 @@ let value_descriptions ~loc env ~mark subst id ~mmodes vd1 vd2 = (* Inclusion between type declarations *) -let type_declarations ~loc env ~mark subst id decl1 decl2 = - let mark = mark_positive mark in +let type_declarations ~loc env ~direction subst id decl1 decl2 = + let mark = Directionality.mark_as_used direction in if mark then Env.mark_type_used decl1.type_uid; let decl2 = Subst.type_declaration subst decl2 in @@ -180,8 +251,8 @@ let type_declarations ~loc env ~mark subst id decl1 decl2 = (* Inclusion between extension constructors *) -let extension_constructors ~loc env ~mark subst id ext1 ext2 = - let mark = mark_positive mark in +let extension_constructors ~loc env ~direction subst id ext1 ext2 = + let mark = Directionality.mark_as_used direction in let ext2 = Subst.extension_constructor subst ext2 in match Includecore.extension_constructors ~loc env ~mark id ext1 ext2 with | None -> Ok Tcoerce_none @@ -505,24 +576,8 @@ and shallow_module_paths env subst p1 mty2 p2 = | Mty_alias _ | Mty_ident _ | Mty_signature _ | Mty_functor _ | exception Not_found -> false -(** - In the group of mutual functions below, the [~in_eq] argument is [true] when - we are in fact checking equality of module types. - - The module subtyping relation [A <: B] checks that [A.T = B.T] when [A] - and [B] define a module type [T]. The relation [A.T = B.T] is equivalent - to [(A.T <: B.T) and (B.T <: A.T)], but checking both recursively would lead - to an exponential slowdown (see #10598 and #10616). - To avoid this issue, when [~in_eq] is [true], we compute a coarser relation - [A << B] which is the same as [A <: B] except that module types [T] are - checked only for [A.T << B.T] and not the reverse. - Thus, we can implement a cheap module type equality check [A.T = B.T] by - computing [(A.T << B.T) and (B.T << A.T)], avoiding the exponential slowdown - described above. -*) - -let rec modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 shape = - match try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 shape with +let rec modtypes ~direction ~loc env subst ~modes mty1 mty2 shape = + match try_modtypes ~direction ~loc env subst ~modes mty1 mty2 shape with | Ok _ as ok -> ok | Error reason -> let mty1 = Subst.Lazy.force_modtype mty1 in @@ -531,7 +586,7 @@ let rec modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 shape = in Error Error.(diff mty1 mty2 reason) -and try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 orig_shape = +and try_modtypes ~direction ~loc env subst ~modes mty1 mty2 orig_shape = let open Subst.Lazy in (* Do a quick nominal comparison for simple types and if that fails, try to unfold one of them. For structured types, do a deep comparison. *) @@ -553,7 +608,7 @@ and try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 orig_shape = | p1 -> begin match Env.find_module_lazy p1 env with | md -> begin - match strengthened_modtypes ~in_eq ~loc ~aliasable:true env ~mark + match strengthened_modtypes ~direction ~loc ~aliasable:true env subst ~modes md.md_type p1 mty2 orig_shape with | Ok _ as x -> x @@ -565,7 +620,7 @@ and try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 orig_shape = end | (Mty_signature sig1, Mty_signature sig2) -> begin match - signatures ~in_eq ~loc env ~mark subst ~modes sig1 sig2 orig_shape + signatures ~direction ~loc env subst ~modes sig1 sig2 orig_shape with | Ok _ as ok -> ok | Error e -> Error (Error.Signature e) @@ -574,7 +629,8 @@ and try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 orig_shape = | Mty_functor (param1, res1), Mty_functor (param2, res2) -> walk_locks ~env ~item:Module modes; let cc_arg, env, subst = - functor_param ~in_eq ~loc env ~mark:(negate_mark mark) + let direction = Directionality.negate direction in + functor_param ~direction ~loc env subst param1 param2 in let var, res_shape = @@ -592,7 +648,7 @@ and try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 orig_shape = var, Shape.app orig_shape ~arg:shape_var in let cc_res = - modtypes ~in_eq ~loc env ~mark subst res1 res2 res_shape + modtypes ~direction ~loc env subst res1 res2 res_shape ~modes:(Legacy None) in begin match cc_arg, cc_res with @@ -650,7 +706,7 @@ and try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 orig_shape = in match red with | Some (mty1,mty2) -> - try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 orig_shape + try_modtypes ~direction ~loc env subst ~modes mty1 mty2 orig_shape | None -> (* Report error *) match mty1, mty2 with @@ -682,7 +738,7 @@ and try_modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 orig_shape = (* Functor parameters *) -and functor_param ~in_eq ~loc env ~mark subst param1 param2 = +and functor_param ~direction ~loc env subst param1 param2 = let open Subst.Lazy in match param1, param2 with | Unit, Unit -> @@ -691,7 +747,7 @@ and functor_param ~in_eq ~loc env ~mark subst param1 param2 = let arg2' = Subst.Lazy.modtype Keep subst arg2 in let cc_arg = match - modtypes ~in_eq ~loc env ~mark Subst.identity arg2' arg1 + modtypes ~direction ~loc env Subst.identity arg2' arg1 Shape.dummy_mod ~modes:(Legacy None) with | Ok (cc, _) -> Ok cc @@ -721,22 +777,22 @@ and equate_one_functor_param subst env arg2' name1 name2 = | None, None -> env, subst -and strengthened_modtypes ~in_eq ~loc ~aliasable env ~mark +and strengthened_modtypes ~direction ~loc ~aliasable env subst ~modes mty1 path1 mty2 shape = let mty1 = Mtype.strengthen_lazy ~aliasable mty1 path1 in - modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 shape + modtypes ~direction ~loc env subst ~modes mty1 mty2 shape -and strengthened_module_decl ~loc ~aliasable env ~mark +and strengthened_module_decl ~loc ~aliasable ~direction env subst ~mmodes md1 path1 md2 shape = let md1 = Subst.Lazy.of_module_decl md1 in let md1 = Mtype.strengthen_lazy_decl ~aliasable md1 path1 in let mty2 = Subst.Lazy.of_modtype md2.md_type in let modes = mmodes in - modtypes ~in_eq:false ~loc env ~mark subst ~modes md1.md_type mty2 shape + modtypes ~direction ~loc env subst ~modes md1.md_type mty2 shape (* Inclusion between signatures *) -and signatures ~in_eq ~loc env ~mark subst ~modes sig1 sig2 mod_shape = +and signatures ~direction ~loc env subst ~modes sig1 sig2 mod_shape = let open Subst.Lazy in (* Environment used to check inclusion of components *) let sig1 = force_signature_once sig1 in @@ -764,7 +820,7 @@ and signatures ~in_eq ~loc env ~mark subst ~modes sig1 sig2 mod_shape = (* Do the pairing and checking, and return the final coercion *) let paired, unpaired, subst = pair_components subst comps1 sig2 in let d = - signature_components ~in_eq ~loc ~mark new_env subst mod_shape + signature_components ~direction ~loc new_env subst mod_shape Shape.Map.empty ~mmodes:modes (List.rev paired) in @@ -789,19 +845,19 @@ and signatures ~in_eq ~loc env ~mark subst ~modes sig1 sig2 mod_shape = (* Inclusion between signature components *) and signature_components : - 'a. in_eq:_ -> loc:_ -> mark:_ -> _ -> _ -> _ -> _ -> mmodes:_ -> (_ * _ * 'a) list -> 'a Sign_diff.t = - fun ~in_eq ~loc ~mark env subst orig_shape shape_map ~mmodes paired -> + 'a. direction:_ -> loc:_ -> _ -> _ -> _ -> _ -> mmodes:_ -> (_ * _ * 'a) list -> 'a Sign_diff.t = + fun ~direction ~loc env subst orig_shape shape_map ~mmodes paired -> let open Subst.Lazy in match paired with | [] -> Sign_diff.{ empty with shape_map } | (sigi1, sigi2, pos) :: rem -> let shape_modified = ref false in - let id, item, shape_map, present_at_runtime = + let id, item, paired_uids, shape_map, present_at_runtime = match sigi1, sigi2 with | Sig_value(id1, valdecl1, _) ,Sig_value(_id2, valdecl2, _) -> let mmodes = append_ldot (Ident.name id1) mmodes in let item = - value_descriptions ~loc env ~mark subst id1 ~mmodes + value_descriptions ~loc ~direction env subst id1 ~mmodes (Subst.Lazy.force_value_description valdecl1) (Subst.Lazy.force_value_description valdecl2) in @@ -811,25 +867,26 @@ and signature_components : | _ -> true in let shape_map = Shape.Map.add_value_proj shape_map id1 orig_shape in - id1, item, shape_map, present_at_runtime + let paired_uids = (valdecl1.val_uid, valdecl2.val_uid) in + id1, item, paired_uids, shape_map, present_at_runtime | Sig_type(id1, tydec1, _, _), Sig_type(_id2, tydec2, _, _) -> let item = - type_declarations ~loc env ~mark subst id1 tydec1 tydec2 + type_declarations ~loc ~direction env subst id1 tydec1 tydec2 in let item = mark_error_as_unrecoverable item in (* Right now we don't filter hidden constructors / labels from the shape. *) let shape_map = Shape.Map.add_type_proj shape_map id1 orig_shape in - id1, item, shape_map, false + id1, item, (tydec1.type_uid, tydec2.type_uid), shape_map, false | Sig_typext(id1, ext1, _, _), Sig_typext(_id2, ext2, _, _) -> let item = - extension_constructors ~loc env ~mark subst id1 ext1 ext2 + extension_constructors ~loc ~direction env subst id1 ext1 ext2 in let item = mark_error_as_unrecoverable item in let shape_map = Shape.Map.add_extcons_proj shape_map id1 orig_shape in - id1, item, shape_map, true + id1, item, (ext1.ext_uid, ext2.ext_uid), shape_map, true | Sig_module(id1, pres1, mty1, _, _), Sig_module(_, pres2, mty2, _, _) -> begin let mmodes = append_ldot (Ident.name id1) mmodes in @@ -837,7 +894,7 @@ and signature_components : Shape.(proj orig_shape (Item.module_ id1)) in let item = - module_declarations ~in_eq ~loc env ~mark subst id1 mty1 mty2 + module_declarations ~direction ~loc env subst id1 mty1 mty2 ~mmodes orig_shape in let item, shape_map = @@ -862,17 +919,18 @@ and signature_components : | Mp_absent, Mp_present, _ -> assert false in let item = mark_error_as_unrecoverable item in - id1, item, shape_map, present_at_runtime + let paired_uids = (mty1.md_uid, mty2.md_uid) in + id1, item, paired_uids, shape_map, present_at_runtime end | Sig_modtype(id1, info1, _), Sig_modtype(_id2, info2, _) -> let item = - modtype_infos ~in_eq ~loc env ~mark subst id1 info1 info2 + modtype_infos ~direction ~loc env subst id1 info1 info2 in let shape_map = Shape.Map.add_module_type_proj shape_map id1 orig_shape in let item = mark_error_as_unrecoverable item in - id1, item, shape_map, false + id1, item, (info1.mtd_uid, info2.mtd_uid), shape_map, false | Sig_class(id1, decl1, _, _), Sig_class(_id2, decl2, _, _) -> walk_locks ~env ~item:Class (append_ldot (Ident.name id1) mmodes); let item = @@ -882,7 +940,7 @@ and signature_components : Shape.Map.add_class_proj shape_map id1 orig_shape in let item = mark_error_as_unrecoverable item in - id1, item, shape_map, true + id1, item, (decl1.cty_uid, decl2.cty_uid), shape_map, true | Sig_class_type(id1, info1, _, _), Sig_class_type(_id2, info2, _, _) -> let item = class_type_declarations ~loc env subst info1 info2 @@ -891,7 +949,7 @@ and signature_components : let shape_map = Shape.Map.add_class_type_proj shape_map id1 orig_shape in - id1, item, shape_map, false + id1, item, (info1.clty_uid, info2.clty_uid), shape_map, false | _ -> assert false in @@ -899,6 +957,25 @@ and signature_components : let first = match item with | Ok x -> + begin match direction with + | { Directionality.in_eq = true; pos = Negative } + | { Directionality.mark_as_used = Mark_neither; _ } -> + (* We do not store paired uids when checking for reverse + module-type inclusion as it would introduce duplicates. *) + () + | { Directionality.pos; _} -> + let paired_uids = + let elt1, elt2 = paired_uids in + match pos with + | Negative -> + (Cmt_format.Declaration_to_declaration, elt2, elt1) + | Positive -> + (Cmt_format.Declaration_to_declaration, elt1, elt2) + | Strictly_positive -> + (Cmt_format. Definition_to_declaration, elt1, elt2) + in + Cmt_format.record_declaration_dependency paired_uids + end; let runtime_coercions = if present_at_runtime then [pos,x] else [] in @@ -912,7 +989,7 @@ and signature_components : in let rest = if continue then - signature_components ~in_eq ~loc ~mark env subst + signature_components ~direction ~loc env subst orig_shape shape_map ~mmodes rem else let rem = List.map @@ -926,7 +1003,7 @@ and signature_components : in Sign_diff.merge first rest -and module_declarations ~in_eq ~loc env ~mark subst id1 ~mmodes md1 md2 orig_shape = +and module_declarations ~direction ~loc env subst id1 ~mmodes md1 md2 orig_shape = let open Subst.Lazy in Builtin_attributes.check_alerts_inclusion ~def:md1.md_loc @@ -935,15 +1012,15 @@ and module_declarations ~in_eq ~loc env ~mark subst id1 ~mmodes md1 md2 orig_s md1.md_attributes md2.md_attributes (Ident.name id1); let p1 = Path.Pident id1 in - if mark_positive mark then + if Directionality.mark_as_used direction then Env.mark_module_used md1.md_uid; let modes = mmodes in - strengthened_modtypes ~in_eq ~loc ~aliasable:true env ~mark subst ~modes + strengthened_modtypes ~direction ~loc ~aliasable:true env subst ~modes md1.md_type p1 md2.md_type orig_shape (* Inclusion between module type specifications *) -and modtype_infos ~in_eq ~loc env ~mark subst id info1 info2 = +and modtype_infos ~direction ~loc env subst id info1 info2 = let open Subst.Lazy in Builtin_attributes.check_alerts_inclusion ~def:info1.mtd_loc @@ -957,10 +1034,10 @@ and modtype_infos ~in_eq ~loc env ~mark subst id info1 info2 = (None, None) -> Ok Tcoerce_none | (Some _, None) -> Ok Tcoerce_none | (Some mty1, Some mty2) -> - check_modtype_equiv ~in_eq ~loc env ~mark mty1 mty2 + check_modtype_equiv ~direction ~loc env mty1 mty2 | (None, Some mty2) -> let mty1 = Mty_ident(Path.Pident id) in - check_modtype_equiv ~in_eq ~loc env ~mark mty1 mty2 in + check_modtype_equiv ~direction ~loc env mty1 mty2 in match r with | Ok _ as ok -> ok | Error e -> @@ -968,9 +1045,11 @@ and modtype_infos ~in_eq ~loc env ~mark subst id info1 info2 = let info2 = Subst.Lazy.force_modtype_decl info2 in Error Error.(Module_type_declaration (diff info1 info2 e)) -and check_modtype_equiv ~in_eq ~loc env ~mark mty1 mty2 = +and check_modtype_equiv ~direction ~loc env mty1 mty2 = + let nested_eq = direction.Directionality.in_eq in + let direction = Directionality.enter_eq direction in let c1 = - modtypes ~in_eq:true ~loc env ~mark Subst.identity mty1 mty2 Shape.dummy_mod + modtypes ~direction ~loc env Subst.identity mty1 mty2 Shape.dummy_mod ~modes:All in let c2 = @@ -978,11 +1057,11 @@ and check_modtype_equiv ~in_eq ~loc env ~mark mty1 mty2 = the outer module type is the one responsible for checking the other side of the equivalence. *) - if in_eq then None + if nested_eq then None else - let mark = negate_mark mark in + let direction = Directionality.negate direction in Some ( - modtypes ~in_eq:true ~loc env ~mark Subst.identity ~modes:All + modtypes ~direction ~loc env Subst.identity ~modes:All mty2 mty1 Shape.dummy_mod ) in @@ -997,10 +1076,10 @@ and check_modtype_equiv ~in_eq ~loc env ~mark mty1 mty2 = | Error less_than, Some Error greater_than -> Error Error.(Incomparable {less_than; greater_than}) -let include_functor_signatures ~loc env ~mark subst sig1 sig2 mod_shape = +let include_functor_signatures ~direction ~loc env subst sig1 sig2 mod_shape = let _, _, comps1 = build_component_table (fun _pos name -> name) sig1 in let paired, unpaired, subst = pair_components subst comps1 sig2 in - let d = signature_components ~in_eq:false ~loc ~mark env subst mod_shape + let d = signature_components ~direction ~loc env subst mod_shape Shape.Map.empty ~mmodes:(Legacy None) (List.rev paired) in @@ -1021,21 +1100,21 @@ let can_alias env path = no_apply path && not (Env.is_functor_arg path env) -let signatures ~in_eq ~loc env ~mark subst sig1 sig2 mod_shape = +let signatures ~direction ~loc env subst sig1 sig2 mod_shape = let sig1 = Subst.Lazy.of_signature sig1 in let sig2 = Subst.Lazy.of_signature sig2 in - signatures ~in_eq ~loc env ~mark subst sig1 sig2 mod_shape + signatures ~direction ~loc env subst sig1 sig2 mod_shape -let modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 shape = +let modtypes ~direction ~loc env subst ~modes mty1 mty2 shape = let mty1 = Subst.Lazy.of_modtype mty1 in let mty2 = Subst.Lazy.of_modtype mty2 in - modtypes ~in_eq ~loc env ~mark subst ~modes mty1 mty2 shape + modtypes ~direction ~loc env subst ~modes mty1 mty2 shape -let strengthened_modtypes ~in_eq ~loc ~aliasable env ~mark +let strengthened_modtypes ~direction ~loc ~aliasable env subst mty1 path1 mty2 shape = let mty1 = Subst.Lazy.of_modtype mty1 in let mty2 = Subst.Lazy.of_modtype mty2 in - strengthened_modtypes ~in_eq ~loc ~aliasable env ~mark subst mty1 + strengthened_modtypes ~direction ~loc ~aliasable env subst mty1 path1 mty2 shape type explanation = Env.t * Error.all @@ -1055,7 +1134,8 @@ exception Apply_error of { let check_modtype_inclusion_raw ~loc env mty1 path1 mty2 = let aliasable = can_alias env path1 in - strengthened_modtypes ~in_eq:false ~loc ~aliasable env ~mark:Mark_both + let direction = Directionality.unknown ~mark:true in + strengthened_modtypes ~direction ~loc ~aliasable env Subst.identity ~modes:(Legacy None) mty1 path1 mty2 Shape.dummy_mod |> Result.map fst @@ -1092,8 +1172,9 @@ let () = let compunit0 ~comparison env ~mark impl_name impl_sig intf_name intf_sig unit_shape = + let direction = Directionality.strictly_positive ~mark ~both:false in match - signatures ~in_eq:false ~loc:(Location.in_file impl_name) env ~mark + signatures ~direction ~loc:(Location.in_file impl_name) env Subst.identity ~modes:(Legacy None) impl_sig intf_sig unit_shape with Result.Error reasons -> let diff = Error.diff impl_name intf_name reasons in @@ -1110,7 +1191,7 @@ let compunit = compunit0 ~comparison:Implementation_vs_interface let compunit_as_argument env arg_name arg_sig param_name param_sig = let cc, _shape = compunit0 env arg_name arg_sig param_name param_sig Shape.dummy_mod - ~comparison:Argument_vs_parameter ~mark:Mark_positive + ~comparison:Argument_vs_parameter ~mark:true in cc @@ -1214,7 +1295,8 @@ module Functor_inclusion_diff = struct let res, _, _ = let mty1 = Subst.Lazy.of_functor_parameter mty1 in let mty2 = Subst.Lazy.of_functor_parameter mty2 in - functor_param ~in_eq:false ~loc st.env ~mark:Mark_neither + let direction = Directionality.unknown ~mark:false in + functor_param ~direction ~loc st.env st.subst mty1 mty2 in res @@ -1308,8 +1390,9 @@ module Functor_app_diff = struct | Unit, Named _ | (Anonymous | Named _), Unit -> Result.Error (Error.Incompatible_params(arg,param)) | ( Anonymous | Named _ | Empty_struct ), Named (_, param) -> + let direction = Directionality.unknown ~mark:false in match - modtypes ~in_eq:false ~loc state.env ~mark:Mark_neither + modtypes ~direction ~loc state.env state.subst ~modes:(Legacy None) arg_mty param Shape.dummy_mod with @@ -1331,45 +1414,61 @@ end (* Hide the context and substitution parameters to the outside world *) -let modtypes_with_shape ~shape ~loc env ~mark ~modes mty1 mty2 = - match modtypes ~in_eq:false ~loc env ~mark +let modtypes_constraint ~shape ~loc env ~mark ~modes mty1 mty2 = + (* modtypes with shape is used when typing module expressions in [Typemod] *) + let direction = Directionality.strictly_positive ~mark ~both:true in + match modtypes ~direction ~loc env Subst.identity ~modes mty1 mty2 shape with | Ok (cc, shape) -> cc, shape | Error reason -> raise (Error (env, Error.(In_Module_type reason))) let modtypes ~loc env ~mark ~modes mty1 mty2 = - match modtypes ~in_eq:false ~loc env ~mark + let direction = Directionality.unknown ~mark in + match modtypes ~direction ~loc env Subst.identity ~modes mty1 mty2 Shape.dummy_mod with | Ok (cc, _) -> cc | Error reason -> raise (Error (env, Error.(In_Module_type reason))) -let signatures env ~mark ~modes sig1 sig2 = - match signatures ~in_eq:false ~loc:Location.none env ~mark +let gen_signatures env ~direction ~modes sig1 sig2 = + match signatures ~direction ~loc:Location.none env Subst.identity ~modes sig1 sig2 Shape.dummy_mod with | Ok (cc, _) -> cc | Error reason -> raise (Error(env,Error.(In_Signature reason))) +let signatures env ~mark ~modes sig1 sig2 = + let direction = Directionality.unknown ~mark in + gen_signatures env ~direction ~modes sig1 sig2 + +let check_implementation env ~modes impl intf = + let direction = + Directionality.strictly_positive ~mark:true ~both:false + in + ignore (gen_signatures env ~direction ~modes impl intf) + let include_functor_signatures env ~mark sig1 sig2 = let sig1 = List.map Subst.Lazy.of_signature_item sig1 in let sig2 = List.map Subst.Lazy.of_signature_item sig2 in - match include_functor_signatures ~loc:Location.none env ~mark + let direction = Directionality.unknown ~mark in + match include_functor_signatures ~direction ~loc:Location.none env Subst.identity sig1 sig2 Shape.dummy_mod with | Ok cc -> cc | Error reason -> raise (Error(env,Error.(In_Include_functor_signature reason))) let type_declarations ~loc env ~mark id decl1 decl2 = - match type_declarations ~loc env ~mark Subst.identity id decl1 decl2 with + let direction = Directionality.unknown ~mark in + match type_declarations ~loc env ~direction Subst.identity id decl1 decl2 with | Ok _ -> () | Error (Error.Core reason) -> raise (Error(env,Error.(In_Type_declaration(id,reason)))) | Error _ -> assert false let strengthened_module_decl ~loc ~aliasable env ~mark ~mmodes md1 path1 md2 = - match strengthened_module_decl ~loc ~aliasable env ~mark Subst.identity + let direction = Directionality.unknown ~mark in + match strengthened_module_decl ~loc ~aliasable ~direction env Subst.identity ~mmodes md1 path1 md2 Shape.dummy_mod with | Ok (x, _shape) -> x | Error mdiff -> @@ -1384,7 +1483,8 @@ let expand_module_alias ~strengthen env path = let check_modtype_equiv ~loc env id mty1 mty2 = let mty1' = Subst.Lazy.of_modtype mty1 in let mty2' = Subst.Lazy.of_modtype mty2 in - match check_modtype_equiv ~in_eq:false ~loc env ~mark:Mark_both mty1' mty2' with + let direction = Directionality.unknown ~mark:true in + match check_modtype_equiv ~direction ~loc env mty1' mty2' with | Ok _ -> () | Error e -> raise (Error(env, diff --git a/typing/includemod.mli b/typing/includemod.mli index 4100f806d98..b3f21f8c719 100644 --- a/typing/includemod.mli +++ b/typing/includemod.mli @@ -18,18 +18,6 @@ open Typedtree open Types -(** Type describing which arguments of an inclusion to consider as used - for the usage warnings. [Mark_both] is the default. *) -type mark = - | Mark_both - (** Mark definitions used from both arguments *) - | Mark_positive - (** Mark definitions used from the positive (first) argument *) - | Mark_negative - (** Mark definitions used from the negative (second) argument *) - | Mark_neither - (** Do not mark definitions used from either argument *) - module Error: sig type ('elt,'explanation) diff = { @@ -155,15 +143,27 @@ type modes = Includecore.mmodes (* Typechecking *) val modtypes: - loc:Location.t -> Env.t -> mark:mark -> modes:modes -> + loc:Location.t -> Env.t -> mark:bool -> modes:modes -> module_type -> module_type -> module_coercion -val modtypes_with_shape: - shape:Shape.t -> loc:Location.t -> Env.t -> mark:mark -> modes:modes -> +(** [modtypes_constraint ~shape ~loc env ~mark exp_modtype constraint_modtype] + checks that [exp_modtype] is a subtype of [constraint_modtype], and returns + the module coercion and the shape of the constrained module. + It also marks as used paired items in positive position in [exp_modtype], + and also paired items in negative position in [constraint_modtype]. + This marking in negative position allows to raise an [unused item] warning + whenever an item in a functor parameter in [constraint_modtype] does not + exist in [exp_modtypes]. This behaviour differs from the one in + {!check_implementation} and {!compunit} which assumes that is not + appropriate to raise warning about the interface file while typechecking the + implementation file. +*) +val modtypes_constraint: + shape:Shape.t -> loc:Location.t -> Env.t -> mark:bool -> modes:modes -> module_type -> module_type -> module_coercion * Shape.t val strengthened_module_decl: - loc:Location.t -> aliasable:bool -> Env.t -> mark:mark -> mmodes:modes -> + loc:Location.t -> aliasable:bool -> Env.t -> mark:bool -> mmodes:modes -> module_declaration -> Path.t -> module_declaration -> module_coercion val check_modtype_inclusion : @@ -176,21 +176,24 @@ val check_modtype_inclusion : val check_modtype_equiv: loc:Location.t -> Env.t -> Ident.t -> module_type -> module_type -> unit -val signatures: Env.t -> mark:mark -> modes:modes -> +val signatures: Env.t -> mark:bool -> modes:modes -> signature -> signature -> module_coercion -val include_functor_signatures : Env.t -> mark:mark -> +val include_functor_signatures : Env.t -> mark:bool -> signature -> signature -> (Ident.t * module_coercion) list +val check_implementation: Env.t -> modes:modes -> signature -> signature -> unit +(** Check an implementation against an interface *) + val compunit: - Env.t -> mark:mark -> string -> signature -> + Env.t -> mark:bool -> string -> signature -> string -> signature -> Shape.t -> module_coercion * Shape.t val compunit_as_argument: Env.t -> string -> signature -> string -> signature -> module_coercion val type_declarations: - loc:Location.t -> Env.t -> mark:mark -> + loc:Location.t -> Env.t -> mark:bool -> Ident.t -> type_declaration -> type_declaration -> unit val print_coercion: Format.formatter -> module_coercion -> unit diff --git a/typing/shape.ml b/typing/shape.ml index 7caed292b64..2f4da35a260 100644 --- a/typing/shape.ml +++ b/typing/shape.ml @@ -16,7 +16,7 @@ module Uid = struct type t = | Compilation_unit of string - | Item of { comp_unit: string; id: int } + | Item of { comp_unit: string; id: int; from: Unit_info.intf_or_impl } | Internal | Predef of string | Unboxed_version of t @@ -29,7 +29,10 @@ module Uid = struct | Compilation_unit s1, Compilation_unit s2 -> String.compare s1 s2 | Item c1, Item c2 -> let c = Int.compare c1.id c2.id in - if c <> 0 then c else String.compare c1.comp_unit c2.comp_unit + let c = + if c <> 0 then c else String.compare c1.comp_unit c2.comp_unit + in + if c <> 0 then c else Stdlib.compare c1.from c2.from | Internal, Internal -> 0 | Predef s1, Predef s2 -> String.compare s1 s2 | Unboxed_version t1, Unboxed_version t2 -> compare t1 t2 @@ -50,11 +53,16 @@ module Uid = struct let hash (x : t) = Hashtbl.hash x + let pp_intf_or_impl fmt = function + | Unit_info.Intf -> Format.pp_print_string fmt "[intf]" + | Unit_info.Impl -> () + let rec print fmt = function | Internal -> Format.pp_print_string fmt "" | Predef name -> Format.fprintf fmt "" name | Compilation_unit s -> Format.pp_print_string fmt s - | Item { comp_unit; id } -> Format.fprintf fmt "%s.%d" comp_unit id + | Item { comp_unit; id; from } -> + Format.fprintf fmt "%a%s.%d" pp_intf_or_impl from comp_unit id | Unboxed_version t -> Format.fprintf fmt "%a#" print t let output oc t = @@ -67,14 +75,15 @@ module Uid = struct let reinit () = id := (-1) let mk ~current_unit = - incr id; - let comp_unit = + let comp_unit, from = + let open Unit_info in match current_unit with - | Some cu -> - Unit_info.modname cu |> Compilation_unit.full_path_as_string - | None -> "" + | None -> "", Impl + | Some ui -> + Compilation_unit.full_path_as_string (modname ui), kind ui in - Item { comp_unit; id = !id } + incr id; + Item { comp_unit; id = !id; from } let of_compilation_unit_id id = Compilation_unit (id |> Compilation_unit.full_path_as_string) diff --git a/typing/shape.mli b/typing/shape.mli index 3a18698cb0b..a75cb0011fd 100644 --- a/typing/shape.mli +++ b/typing/shape.mli @@ -43,9 +43,9 @@ [cmt_format.cmt_uid_to_decl] table of the corresponding compilation unit. See: - - {{: https://icfp22.sigplan.org/details/mlfamilyworkshop-2022-papers/10/Module-Shapes-for-Modern-Tooling } + - {{:https://icfp22.sigplan.org/details/mlfamilyworkshop-2022-papers/10/Module-Shapes-for-Modern-Tooling} the design document} - - {{: https://www.lix.polytechnique.fr/Labo/Gabriel.Scherer/research/shapes/2022-ml-workshop-shapes-talk.pdf } + - {{:https://www.lix.polytechnique.fr/Labo/Gabriel.Scherer/research/shapes/2022-ml-workshop-shapes-talk.pdf} a talk about the reduction strategy *) @@ -57,7 +57,10 @@ module Uid : sig type t = private | Compilation_unit of string - | Item of { comp_unit: string; id: int } + | Item of { + comp_unit: string; + id: int; + from: Unit_info.intf_or_impl } | Internal | Predef of string | Unboxed_version of t diff --git a/typing/typemod.ml b/typing/typemod.ml index 06eb5a73a69..9518ee958a7 100644 --- a/typing/typemod.ml +++ b/typing/typemod.ml @@ -147,7 +147,7 @@ let extract_sig_functor_open funct_body env loc mty sig_acc = in let coercion = try - Includemod.include_functor_signatures ~mark:Mark_both env + Includemod.include_functor_signatures ~mark:true env sig_acc sg_param with Includemod.Error msg -> raise (Error(loc, env, Not_included_functor msg)) @@ -316,7 +316,7 @@ let check_type_decl env sg loc id row_id newdecl decl = | Some fresh_row_id -> Env.add_type ~check:false fresh_row_id newdecl env in let env = Env.add_signature sg env in - Includemod.type_declarations ~mark:Mark_both ~loc env fresh_id newdecl decl; + Includemod.type_declarations ~mark:true ~loc env fresh_id newdecl decl; ignore (Typedecl.check_coherence env loc path newdecl) let make_variance p n i = @@ -833,7 +833,7 @@ let merge_constraint initial_env loc sg lid constr = in let md'' = { md' with md_type = mty } in let newmd = Mtype.strengthen_decl ~aliasable:false md'' path in - ignore(Includemod.modtypes ~mark:Mark_both ~loc sig_env + ignore(Includemod.modtypes ~mark:true ~loc sig_env ~modes:(Legacy None) newmd.md_type md.md_type); return ~replace_by:(Some(Sig_module(id, pres, newmd, rs, priv))) @@ -843,7 +843,7 @@ let merge_constraint initial_env loc sg lid constr = let sig_env = Env.add_signature sg_for_env outer_sig_env in let aliasable = not (Env.is_functor_arg path sig_env) in ignore - (Includemod.strengthened_module_decl ~loc ~mark:Mark_both + (Includemod.strengthened_module_decl ~loc ~mark:true ~aliasable sig_env ~mmodes:(Legacy None) md' path md); real_ids := [Pident id]; return ~replace_by:None @@ -1732,7 +1732,7 @@ and transl_modtype_aux env smty = try ignore (Includemod.modtypes ~loc env ~modes:(Legacy None) - ~mark:Includemod.Mark_both md.md_type tmty.mty_type); + ~mark:true md.md_type tmty.mty_type); mkmty (Tmty_strengthen (tmty, path, mod_id)) (Mty_strengthen @@ -2425,8 +2425,8 @@ let check_recmodule_inclusion env bindings = and mty_actual' = subst_and_strengthen scope s id mty_actual in let coercion, shape = try - Includemod.modtypes_with_shape ~shape - ~loc:modl.mod_loc ~mark:Mark_both + Includemod.modtypes_constraint ~shape + ~loc:modl.mod_loc ~mark:true env ~modes:(Legacy None) mty_actual' mty_decl' with Includemod.Error msg -> raise(Error(modl.mod_loc, env, Not_included msg)) in @@ -2517,14 +2517,13 @@ let package_subtype env p1 fl1 p2 fl2 = | exception Error(_, _, Cannot_scrape_package_type _) -> false | mty1, mty2 -> let loc = Location.none in - match Includemod.modtypes ~loc ~mark:Mark_both env ~modes:All mty1 mty2 with + match Includemod.modtypes ~loc ~mark:true env ~modes:All mty1 mty2 with | Tcoerce_none -> true | _ | exception Includemod.Error _ -> false let () = Ctype.package_subtype := package_subtype let wrap_constraint_package env mark arg held_locks mty explicit = - let mark = if mark then Includemod.Mark_both else Includemod.Mark_neither in let mty1 = Subst.modtype Keep Subst.identity arg.mod_type in let mty2 = Subst.modtype Keep Subst.identity mty in let coercion = @@ -2540,10 +2539,9 @@ let wrap_constraint_package env mark arg held_locks mty explicit = let wrap_constraint_with_shape env mark arg held_locks mty shape explicit = - let mark = if mark then Includemod.Mark_both else Includemod.Mark_neither in let coercion, shape = try - Includemod.modtypes_with_shape ~shape ~loc:arg.mod_loc env ~mark + Includemod.modtypes_constraint ~shape ~loc:arg.mod_loc env ~mark ~modes:(Legacy held_locks) arg.mod_type mty with Includemod.Error msg -> raise(Error(arg.mod_loc, env, Not_included msg)) in @@ -2896,7 +2894,7 @@ and type_one_application ~ctx:(apply_loc,sfunct,md_f,args) arg = Some { shape = arg_shape; path = arg_path; arg; held_locks } } -> let coercion = try Includemod.modtypes - ~loc:arg.mod_loc ~mark:Mark_both env arg.mod_type mty_param + ~loc:arg.mod_loc ~mark:true env arg.mod_type mty_param ~modes:(Legacy held_locks) with Includemod.Error _ -> apply_error () in @@ -2928,7 +2926,7 @@ and type_one_application ~ctx:(apply_loc,sfunct,md_f,args) in begin match Includemod.modtypes - ~loc:app_loc ~mark:Mark_neither env mty_res nondep_mty + ~loc:app_loc ~mark:false env mty_res nondep_mty ~modes:(Legacy None) with | Tcoerce_none -> () @@ -3776,10 +3774,14 @@ let type_implementation target modulename initial_env ast = raise (Error (Location.in_file sourcefile, initial_env, e)) in let save_cmt_and_cms target annots initial_env cmi shape = + let decl_deps = + (* This is cleared after saving the cmt so we have to save is before *) + Cmt_format.get_declaration_dependencies () + in Cmt_format.save_cmt (Unit_info.cmt target) modulename annots initial_env cmi shape; Cms_format.save_cms (Unit_info.cms target) modulename - annots initial_env shape; + annots initial_env shape decl_deps; gen_annot target annots; in Cmt_format.clear (); @@ -3867,7 +3869,7 @@ let type_implementation target modulename initial_env ast = old_arg_type = arg_type_from_cmi }); let coercion, shape = Profile.record_call "check_sig" (fun () -> - Includemod.compunit initial_env ~mark:Mark_positive + Includemod.compunit initial_env ~mark:true sourcefile sg compiled_intf_file_name dclsig shape) in (* Check the _mli_ against the argument type, since the mli determines @@ -3903,7 +3905,7 @@ let type_implementation target modulename initial_env ast = Warnings.Missing_mli; let coercion, shape = Profile.record_call "check_sig" (fun () -> - Includemod.compunit initial_env ~mark:Mark_positive + Includemod.compunit initial_env ~mark:true sourcefile sg "(inferred signature)" simple_sg shape) in check_nongen_signature finalenv simple_sg; @@ -3958,10 +3960,14 @@ let type_implementation target modulename initial_env ast = ) let save_signature target modname tsg initial_env cmi = + let decl_deps = + (* This is cleared after saving the cmt so we have to save is before *) + Cmt_format.get_declaration_dependencies () + in Cmt_format.save_cmt (Unit_info.cmti target) modname (Cmt_format.Interface tsg) initial_env (Some cmi) None; Cms_format.save_cms (Unit_info.cmsi target) modname - (Cmt_format.Interface tsg) initial_env None + (Cmt_format.Interface tsg) initial_env None decl_deps let cms_register_toplevel_signature_attributes ~sourcefile ~uid ast = cms_register_toplevel_attributes ~sourcefile ~uid ast.psg_items @@ -4070,13 +4076,17 @@ let package_units initial_env objfiles target_cmi modulename = let name = Compilation_unit.to_global_name_without_prefix modulename in let dclsig = Env.read_signature name target_cmi in let cc, _shape = - Includemod.compunit initial_env ~mark:Mark_both + Includemod.compunit initial_env ~mark:true "(obtained by packing)" sg mli dclsig shape in + let decl_deps = + (* This is cleared after saving the cmt so we have to save is before *) + Cmt_format.get_declaration_dependencies () + in Cmt_format.save_cmt (Unit_info.companion_cmt target_cmi) modulename (Cmt_format.Packed (sg, objfiles)) initial_env None (Some shape); Cms_format.save_cms (Unit_info.companion_cms target_cmi) modulename - (Cmt_format.Packed (sg, objfiles)) initial_env (Some shape); + (Cmt_format.Packed (sg, objfiles)) initial_env (Some shape) decl_deps; cc end else begin (* Determine imports *) @@ -4099,10 +4109,14 @@ let package_units initial_env objfiles target_cmi modulename = sg name kind target_cmi (Array.of_list imports) in let sign = Subst.Lazy.force_signature cmi.Cmi_format.cmi_sign in + let decl_deps = + (* This is cleared after saving the cmt so we have to save is before *) + Cmt_format.get_declaration_dependencies () + in Cmt_format.save_cmt (Unit_info.companion_cmt target_cmi) modulename (Cmt_format.Packed (sign, objfiles)) initial_env (Some cmi) (Some shape); Cms_format.save_cms (Unit_info.companion_cms target_cmi) modulename - (Cmt_format.Packed (sign, objfiles)) initial_env (Some shape); + (Cmt_format.Packed (sign, objfiles)) initial_env (Some shape) decl_deps; end; Tcoerce_none end