Skip to content

Commit 5e12cec

Browse files
authored
Merge pull request #525 from FStarLang/protz_dependency_analysis
Revise dependency analysis to be more precise
2 parents a02d57f + e0119d9 commit 5e12cec

File tree

4 files changed

+108
-37
lines changed

4 files changed

+108
-37
lines changed

.github/workflows/linux-x64-hierarchic.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
run: |
1717
echo "CI_INITIAL_TIMESTAMP=$(date '+%s')" >> $GITHUB_ENV
1818
- name: Check out repo
19-
uses: actions/checkout@v3
19+
uses: actions/checkout@v4
2020
- name: Identify the base FStar branch and the notification channel
2121
run: |
2222
echo "FSTAR_BRANCH=$(jq -c -r '.BranchName' .docker/build/config.json)" >> $GITHUB_ENV
@@ -41,7 +41,7 @@ jobs:
4141
DZOMO_GITHUB_TOKEN: ${{ secrets.DZOMO_GITHUB_TOKEN }}
4242
- name: Archive build log
4343
if: ${{ always() }}
44-
uses: actions/upload-artifact@v3
44+
uses: actions/upload-artifact@v4
4545
with:
4646
name: log
4747
path: log.txt

lib/Bundles.ml

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,23 @@ let make_bundles files =
217217
(* A more refined version of direct_dependencies (found above), which
218218
distinguishes between internal and public dependencies. Keeps less dependency
219219
information, too, since it does not need to generate precise error messages.
220-
To be used after Inlining has run. *)
220+
To be used after Inlining has run.
221+
222+
We do not run this on the C grammar (which would presumably be simpler,
223+
because by then we would have built both flavors of headers + C files),
224+
because it does not distinguish between lids and ids, and also because the
225+
grammar is convoluted and makes it hard to access the "name" of a
226+
declaration.
227+
228+
So instead, we anticipate and rely on the fact that:
229+
- to compute the dependencies of the public header, one needs to visit public
230+
(not internal, not private) functions and type declarations, and
231+
- skip the body of functions unless they are "static header", and
232+
- skip the body of type declarations marked as C abstract structs
233+
- to compute the dependencies of the internal header, same deal
234+
- to compute the dependencies of the C header, same deal except all bodies
235+
are visited
236+
*)
221237

222238
module StringSet = Set.Make(String)
223239
module LidSet = Idents.LidSet
@@ -227,11 +243,30 @@ type deps = {
227243
public: StringSet.t;
228244
}
229245

246+
type all_deps = {
247+
h: deps;
248+
internal_h: deps;
249+
c: deps;
250+
}
251+
230252
let empty_deps = { internal = StringSet.empty; public = StringSet.empty }
231253

232254
let drop_dinstinction { internal; public } =
233255
List.of_seq (StringSet.to_seq (StringSet.union internal public))
234256

257+
class record_everything gen_dep = object
258+
inherit [_] reduce
259+
method plus { internal = i1; public = p1 } { internal = i2; public = p2 } =
260+
{ internal = StringSet.union i1 i2; public = StringSet.union p1 p2 }
261+
method zero = empty_deps
262+
method! visit_EQualified _ lid =
263+
gen_dep lid
264+
method! visit_TQualified _ lid =
265+
gen_dep lid
266+
method! visit_TApp () lid _ =
267+
gen_dep lid
268+
end
269+
235270
let direct_dependencies_with_internal files file_of =
236271
(* Set of decls marked as internal *)
237272
let internal = List.fold_left (fun set (_, decls) ->
@@ -247,29 +282,61 @@ let direct_dependencies_with_internal files file_of =
247282
let gen_dep (callee: lident) =
248283
match file_of callee with
249284
| Some f when f <> fst file && not (Helpers.is_primitive callee) ->
250-
(* KPrint.bprintf "In file %s, reference to %a (in file %s)\n" *)
251-
(* (fst file) PrintAst.plid callee f; *)
252-
if LidSet.mem callee internal then
285+
let is_internal = LidSet.mem callee internal in
286+
KPrint.bprintf "In file %s, reference to %a (in %sheader %s)\n"
287+
(fst file) PrintAst.plid callee (if is_internal then "internal " else "") f;
288+
if is_internal then
253289
{ empty_deps with internal = StringSet.singleton f }
254290
else
255291
{ empty_deps with public = StringSet.singleton f }
256292
| _ ->
257293
empty_deps
258294
in
259-
let deps =
260-
(object
261-
inherit [_] reduce
262-
method plus { internal = i1; public = p1 } { internal = i2; public = p2 } =
263-
{ internal = StringSet.union i1 i2; public = StringSet.union p1 p2 }
264-
method zero = empty_deps
265-
method! visit_EQualified _ lid =
266-
gen_dep lid
267-
method! visit_TQualified _ lid =
268-
gen_dep lid
269-
method! visit_TApp _ lid _ =
270-
gen_dep lid
271-
end)#visit_file () file
272-
in
295+
let is_inline_static lid = List.exists (fun p -> Bundle.pattern_matches_lid p lid) !Options.static_header in
296+
let header_deps which = object
297+
inherit (record_everything gen_dep) as super
298+
299+
method! visit_DFunction env cc flags n_cgs n ret name binders body =
300+
let concerns_us =
301+
match which with
302+
| `Public -> not (List.mem Common.Internal flags) && not (List.mem Common.Private flags)
303+
| `Internal -> List.mem Common.Internal flags
304+
in
305+
if concerns_us then
306+
if is_inline_static name then
307+
super#visit_DFunction env cc flags n_cgs n ret name binders body
308+
else
309+
(* ill-typed, but convenient *)
310+
super#visit_DFunction env cc flags n_cgs n ret name binders Helpers.eunit
311+
else
312+
super#zero
313+
314+
method! visit_DType env name flags n_cgs n def =
315+
let concerns_us =
316+
match which with
317+
| `Public -> not (List.mem Common.Internal flags) && not (List.mem Common.Private flags)
318+
| `Internal -> List.mem Common.Internal flags
319+
in
320+
let is_c_abstract_struct = List.mem Common.AbstractStruct flags in
321+
if concerns_us then
322+
if is_c_abstract_struct then
323+
super#visit_DType env name flags n_cgs n (Abbrev TUnit)
324+
else
325+
super#visit_DType env name flags n_cgs n def
326+
else
327+
super#zero
328+
end in
329+
let deps = {
330+
h = (KPrint.bprintf "PUBLIC %s\n" (fst file); header_deps `Public)#visit_file () file;
331+
internal_h = (KPrint.bprintf "INTERNAL %s\n" (fst file); header_deps `Internal)#visit_file () file;
332+
c = (KPrint.bprintf "C %s\n" (fst file); new record_everything gen_dep)#visit_file () file;
333+
} in
334+
335+
if not (StringSet.is_empty deps.h.internal) then
336+
Warn.fatal_error "Unexpected: %s depends on some internal headers: %s\n"
337+
(fst file)
338+
(String.concat ", " (List.of_seq (StringSet.to_seq deps.h.internal)));
339+
273340
StringMap.add (fst file) deps by_file
274341
) StringMap.empty files
275342

lib/CStarToC11.ml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,19 +1522,18 @@ let mk_headers (map: GlobalNames.mapping)
15221522
) [] files in
15231523
List.rev headers
15241524

1525-
let drop_empty_headers deps headers: Bundles.deps Bundles.StringMap.t =
1525+
let drop_empty_headers deps headers: Bundles.all_deps Bundles.StringMap.t =
15261526
let open Bundles in
15271527
(* Refine dependencies to ignore now-gone empty headers. *)
1528-
let not_dropped_internal f = List.exists (function
1529-
| (name, C.Internal _) when f = name -> true
1530-
| _ -> false
1531-
) headers in
1532-
let not_dropped_public f = List.exists (function
1533-
| (name, Public _) when f = name -> true
1534-
| _ -> false
1535-
) headers in
1536-
StringMap.map (fun { internal; public } -> {
1528+
let kept_internal = List.filter_map (function (name, C.Internal _) -> Some name | _ -> None) headers in
1529+
let kept_public = List.filter_map (function (name, C.Public _) -> Some name | _ -> None) headers in
1530+
let not_dropped_internal f = List.mem f kept_internal in
1531+
let not_dropped_public f = List.mem f kept_public in
1532+
let filter_dep { internal; public } = {
15371533
internal = StringSet.filter not_dropped_internal internal;
15381534
public = StringSet.filter not_dropped_public public
1539-
}) deps
1535+
} in
1536+
StringMap.map (fun { h; internal_h; c } ->
1537+
{ h = filter_dep h; internal_h = filter_dep internal_h; c = filter_dep c }
1538+
) deps
15401539

lib/Output.ml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,15 @@ let maybe_create_internal_dir h =
140140
if List.exists (function (_, C11.Internal _) -> true | _ -> false) h then
141141
create_subdir "internal"
142142

143-
let write_c files internal_headers deps =
143+
let write_c files internal_headers (deps: Bundles.all_deps Bundles.StringMap.t) =
144144
Driver.detect_fstar_if ();
145145
Driver.detect_karamel_if ();
146146
List.map (fun file ->
147147
let name, program = file in
148-
let deps = Bundles.StringMap.find name deps in
149-
let deps = List.of_seq (Bundles.StringSet.to_seq deps.Bundles.internal) in
150-
let deps = List.map (fun f -> "internal/" ^ f) deps in
148+
let all_deps = Bundles.StringMap.find name deps in
149+
let internal_deps = List.of_seq (Bundles.StringSet.to_seq all_deps.Bundles.c.Bundles.internal) in
150+
let public_deps = List.of_seq (Bundles.StringSet.to_seq all_deps.Bundles.c.Bundles.public) in
151+
let deps = List.map (fun f -> "internal/" ^ f) internal_deps @ public_deps in
151152
let includes = includes_for ~is_c:true name deps in
152153
let header = string (header ()) ^^ hardline ^^ hardline in
153154
let internal = if Bundles.StringSet.mem name internal_headers then "internal/" else "" in
@@ -170,10 +171,14 @@ let write_c files internal_headers deps =
170171
name
171172
) files
172173

173-
let write_h files public_headers deps =
174+
let write_h files public_headers (deps: Bundles.all_deps Bundles.StringMap.t) =
174175
List.map (fun file ->
175176
let name, program = file in
176-
let { Bundles.public; internal } = Bundles.StringMap.find name deps in
177+
let all_deps = Bundles.StringMap.find name deps in
178+
let { Bundles.public; internal } = match program with
179+
| C11.Internal _ -> all_deps.Bundles.internal_h
180+
| C11.Public _ -> all_deps.Bundles.h
181+
in
177182
let public = List.of_seq (Bundles.StringSet.to_seq public) in
178183
let internal = List.of_seq (Bundles.StringSet.to_seq internal) in
179184
let original_name = name in

0 commit comments

Comments
 (0)