11type t = {
22 builddir : string ;
33 cm_file : string ;
4- cmi_infos : Cmi_format .cmi_infos option ;
5- cmt_infos : Cmt_format .cmt_infos option ;
6- cmti_infos : Cmt_format .cmt_infos option ;
4+ cmi_sign : Types .signature option ;
5+ cmt_struct : Typedtree .structure option ;
6+ cmti_uid_to_decl : Location_dependencies .uid_to_decl option ;
77 location_dependencies : Location_dependencies .t ;
88 modname : string ;
99 sourcepath : string option ;
@@ -12,119 +12,125 @@ type t = {
1212let empty = {
1313 builddir = " !!UNKNOWN_BUILDDIR!!" ;
1414 cm_file = " " ;
15- cmi_infos = None ;
16- cmt_infos = None ;
17- cmti_infos = None ;
15+ cmi_sign = None ;
16+ cmt_struct = None ;
17+ cmti_uid_to_decl = None ;
1818 location_dependencies = Location_dependencies. empty;
1919 modname = " !!UNKNOWN_MODNAME!!" ;
2020 sourcepath = None ;
2121}
2222
23- (* * [init_from_all_cm_infos ~orig ~ cm_file cmi_infos cmt_infos] creates a [t] with:
24- - information from [cmt_infos];
23+ (* * [init_from_all_cm_infos ~cm_file ~ cmi_infos cmt_infos] creates a [t] with:
24+ - information from [cmt_infos] : [builddir], [modname], [sourcepath] ;
2525 - [cm_file];
26- - [cmi_infos];
27- - [cmt_infos = Some cmt_infos] if [orig = `Cmt];
28- - [cmti_infos = Some cmt_infos] if [orig = `Cmti]. *)
29- let init_from_all_cm_infos ~orig ~cm_file cmi_infos cmt_infos =
26+ - [cmi_sign = Some cm_infos.cmi_sign] if [cmi_infos = Some _]; *)
27+ let init_from_all_cm_infos ~cm_file ~cmi_infos cmt_infos =
3028 let builddir = cmt_infos.Cmt_format. cmt_builddir in
3129 let sourcepath =
3230 Option. map (Filename. concat builddir) cmt_infos.cmt_sourcefile
3331 in
3432 let modname = cmt_infos.cmt_modname in
35- let cmt_infos, cmti_infos =
36- match orig with
37- | `Cmt -> Some cmt_infos, None
38- | `Cmti -> None , Some cmt_infos
39- in
33+ let cmi_sign = Option. map (fun Cmi_format. {cmi_sign; _} -> cmi_sign) cmi_infos in
4034 {empty with builddir;
4135 cm_file;
42- cmi_infos;
43- cmt_infos;
44- cmti_infos;
36+ cmi_sign;
4537 modname;
4638 sourcepath}
4739
48- (* * [init_from_cm_file ~orig cm_file] returns an [Ok t] with [t] filled using
49- the [cm_file] (see [init_from_cmt_infos]).
40+ (* * [init_from_cm_file cm_file] returns an [Ok t] with [t] filled with general
41+ info expected for both cmt and cmti files, using the [cm_file] (see
42+ [init_from_all_cm_infos]).
5043 In case the file does not exist or it cannot be read (see
5144 [Cmt_format.read_cmt]) then it returns an [Err msg] with msg a string
5245 describing the issue. *)
53- let init_from_cm_file ~ orig cm_file =
46+ let init_from_cm_file cm_file =
5447 if not (Sys. file_exists cm_file) then Result. error (cm_file ^ " : file not found" )
5548 else
5649 match Cmt_format. read cm_file with
5750 | exception _ -> Result. error (cm_file ^ " : error reading file" )
5851 | _ , None -> Result. error (cm_file ^ " : cmt_infos not found" )
5952 | cmi_infos , Some cmt_infos ->
60- init_from_all_cm_infos ~orig ~cm_file cmi_infos cmt_infos
61- |> Result. ok
53+ let file_infos =
54+ init_from_all_cm_infos ~cm_file ~cmi_infos cmt_infos
55+ in
56+ Result. ok (file_infos, cmt_infos)
6257
6358let ( let* ) x f = Result. bind x f
59+ let ( let+ ) x f = Result. map f x
6460
65- let init cm_file =
66- let * orig =
67- match Filename. extension cm_file with
68- | ".cmt" -> Result. ok `Cmt
69- | ".cmti" -> Result. ok `Cmti
70- | _ -> Result. error (cm_file ^ " : not a .cmti or .cmt file" )
61+ let init_from_cmti_file cmti_file =
62+ let + file_infos, cmt_infos = init_from_cm_file cmti_file in
63+ let cmti_uid_to_decl = Some cmt_infos.cmt_uid_to_decl in
64+ {file_infos with cmti_uid_to_decl}
65+
66+ let init_from_cmt_file cmt_file =
67+ let * file_infos, cmt_infos = init_from_cm_file cmt_file in
68+ let * cmt_struct =
69+ match cmt_infos.cmt_annots with
70+ | Implementation structure -> Result. ok structure
71+ | _ -> Result. error (cmt_file ^ " : does not contain an implementation" )
7172 in
72- let * file_infos = init_from_cm_file ~orig cm_file in
73- let cmi_infos, cmt_infos, cmti_infos =
74- let no_ext = Filename. remove_extension cm_file in
75- match orig with
76- | `Cmt ->
77- let cmi_infos, cmti_infos =
78- init_from_cm_file ~orig: `Cmti (no_ext ^ " .cmti" )
79- |> Result. map (fun {cmi_infos; cmti_infos; _} -> cmi_infos, cmti_infos)
80- |> Result. value ~default: (file_infos.cmi_infos, file_infos.cmti_infos)
81- in
82- cmi_infos, file_infos.cmt_infos, cmti_infos
83- | `Cmti ->
84- let cmt_infos =
85- init_from_cm_file ~orig: `Cmt (no_ext ^ " .cmt" )
86- |> Result. map (fun {cmt_infos; _} -> cmt_infos)
87- |> Result. value ~default: file_infos.cmt_infos
88- in
89- file_infos.cmi_infos, cmt_infos, file_infos.cmti_infos
73+ let cmt_struct = Some cmt_struct in
74+ (* Read the cmti if it exists. We always want to do it in case a user
75+ specified the cmt before the cmti to ensure the location_dependencies
76+ are idempotent. *)
77+ let cmti_uid_to_decl =
78+ let cmti_file = Filename. remove_extension cmt_file ^ " .cmti" in
79+ match init_from_cmti_file cmti_file with
80+ | Error _ -> None
81+ | Ok file_infos -> file_infos.cmti_uid_to_decl
82+ in
83+ let + location_dependencies =
84+ Location_dependencies. init cmt_infos cmti_uid_to_decl
9085 in
91- let * location_dependencies =
92- match orig with
93- | `Cmt -> Location_dependencies. init cmt_infos cmti_infos
94- | `Cmti -> Result. ok Location_dependencies. empty
86+ let file_infos =
87+ {file_infos with cmt_struct; cmti_uid_to_decl; location_dependencies}
9588 in
96- Result. ok {file_infos with cmi_infos;
97- cmt_infos;
98- cmti_infos;
99- location_dependencies}
89+ file_infos, cmt_infos
90+
91+ let init cm_file =
92+ match Filename. extension cm_file with
93+ | ".cmt" ->
94+ let + file_infos, _ = init_from_cmt_file cm_file in
95+ file_infos
96+ | ".cmti" -> (
97+ (* Using cmt_infos is not critical. The intent is to mirror the behavior
98+ on cmt files, where both cmt and cmti are read. *)
99+ let filled_with_cmt_infos =
100+ let cmt_file = Filename. remove_extension cm_file ^ " .cmt" in
101+ let * file_infos, cmt_infos = init_from_cmt_file cmt_file in
102+ let + location_dependencies =
103+ Location_dependencies. init cmt_infos file_infos.cmti_uid_to_decl
104+ in
105+ {file_infos with location_dependencies}
106+ in
107+ match filled_with_cmt_infos with
108+ | Ok {cmt_struct; cmti_uid_to_decl; location_dependencies; _} ->
109+ let + res, _ = init_from_cm_file cm_file in
110+ {res with cmt_struct; cmti_uid_to_decl; location_dependencies}
111+ | Error _ -> init_from_cmti_file cm_file
112+ )
113+ | _ -> Result. error (cm_file ^ " : not a .cmti or .cmt file" )
100114
101115let change_file file_infos cm_file =
102116 let no_ext = Filename. remove_extension cm_file in
103117 assert (no_ext = Filename. remove_extension file_infos.cm_file);
104118 match Filename. extension cm_file, file_infos with
105- | ".cmt" , {cmt_infos =Some cmt_infos ; cmi_infos; cmti_infos; _} ->
106- let res =
107- init_from_all_cm_infos ~orig: `Cmt ~cm_file cmi_infos cmt_infos
108- in
109- let res = {res with cmi_infos; cmti_infos} in
110- let * location_dependencies =
111- Location_dependencies. init res.cmt_infos res.cmti_infos
112- in
113- Result. ok {res with location_dependencies}
114- | ".cmti" , {cmti_infos =Some cmti_infos ; cmi_infos; cmt_infos; _} ->
115- let res =
116- init_from_all_cm_infos ~orig: `Cmti ~cm_file cmi_infos cmti_infos
117- in
118- Result. ok {res with cmt_infos}
119- | _ , {cmi_infos; cmt_infos; cmti_infos; _} -> (* corresponding info is None or invalid extension *)
120- let * res = init cm_file in
121- let choose opt1 opt2 =
122- if Option. is_some opt1 then opt1 else opt2
119+ | ".cmt" , {cmt_struct = (Some _ as cs ); cmi_sign; cmti_uid_to_decl; _} ->
120+ let * res, cmt_infos = init_from_cm_file cm_file in
121+ let + location_dependencies =
122+ match file_infos.location_dependencies with
123+ | [] -> Location_dependencies. init cmt_infos cmti_uid_to_decl
124+ | loc_dep -> (* They have already been computed *)
125+ Result. ok loc_dep
123126 in
124- let cmi_infos = choose res.cmi_infos cmi_infos in
125- let cmt_infos = choose res.cmt_infos cmt_infos in
126- let cmti_infos = choose res.cmti_infos cmti_infos in
127- Result. ok {res with cmi_infos; cmt_infos; cmti_infos}
127+ {res with cmt_struct = cs; cmi_sign; cmti_uid_to_decl; location_dependencies}
128+ | ".cmti" , {cmti_uid_to_decl = (Some _ as cutd ); cmt_struct; location_dependencies; _} ->
129+ let + res, _ = init_from_cm_file cm_file in
130+ {res with cmti_uid_to_decl = cutd; cmt_struct; location_dependencies}
131+ | _ ->
132+ (* invalid extension or the corresponding info is None *)
133+ init cm_file
128134
129135let has_sourcepath file_infos = Option. is_some file_infos.sourcepath
130136
0 commit comments