@@ -332,114 +332,145 @@ let monomorphize_data_types map = object(self)
332332 * order declarations as they are needed, including that of the node we are
333333 * visiting. *)
334334 method private visit_node (under_ref : bool ) (n : node ) =
335- (* Because we have no equirecursive types, this should not loop *)
336- let n = fst3 n, List. map (self#visit_typ under_ref) (snd3 n), thd3 n in
337- let lid, args, cgs = n in
338- (* White, gray or black? *)
339- match Hashtbl. find state n with
340- | exception Not_found ->
341- let chosen_lid, flag = self#lid_of n in
342- if Options. debug " data-types-traversal" then
343- KPrint. bprintf " visiting %a: Not_found --> %a\n " ptyp (fold_tapp n) plid chosen_lid;
344- let flag = if fst3 best_hint = n then thd3 best_hint @ flag else flag in
345- if lid = tuple_lid then begin
346- Hashtbl. add state n (Gray , chosen_lid);
347- (* For tuples, we immediately know how to generate a definition. *)
348- let fields = List. mapi (fun i arg -> Some (self#field_at i), (arg, false )) args in
349- self#record (DType (chosen_lid, [ Common. Private ] @ flag, 0 , 0 , Flat fields));
350- Hashtbl. replace state n (Black , chosen_lid)
351- end else begin
352- (* This specific node has not been visited yet. *)
353- Hashtbl. add state n (Gray , chosen_lid);
354-
355- let subst fields = List. map (fun (field , (t , m )) ->
356- field, (DeBruijn. subst_tn args (DeBruijn. subst_ctn' cgs t), m)
357- ) fields in
358- assert (not (Hashtbl. mem map lid) || not (has_variables args) && not (has_cg_variables cgs));
359- begin match Hashtbl. find map lid with
360- | exception Not_found ->
361- (* Unknown, external non-polymorphic lid, e.g. Prims.int *)
362- Hashtbl. replace state n (Black , chosen_lid)
363- | flags , ((Variant _ | Flat _ | Union _ ) as def ) when under_ref && not (Hashtbl. mem seen_declarations lid) ->
364- (* FORWARD DECLARATION: this is unrelated to monomorphization (but we do it
365- here anyway). An occurrence of `t<ts>*` appears before the definition of `t`; we
366- pick a name, insert a forward declaration for `t<ts>`, then remember that *once we
367- have see the definition of `t`*, we will insert the monomorphized `t___ts` at that
368- specific location.
369-
370- The comment below furthermore tries to explain why we do things this way (as
371- opposed to inserting the monomorphized `t___ts` immediately).
372-
373- Because this looks up a definition in the global map, the
374- definitions are reordered according to the traversal order, which
375- is generally a good idea (we accept more programs!), EXCEPT
376- when the user relies on mutual recursion behind a reference
377- (pointer) type. In that case, following the type dependency graph is
378- generally not a good idea, since we may go from a valid
379- ordering to an invalid one (see tests/MutualStruct.fst). So,
380- the intent here (i.e., when under a ref type) is that:
381- - tuple types ALWAYS get monomorphized on-demand (see
382- above)
383- - abbreviations are fine and won't cause further issues
384- - data types, however, need to have their names allocated and a
385- forward reference inserted (TODO: at most once), then the
386- specific choice of type arguments need to be recorded as
387- something we want to visit later (once we're done with this
388- particular traversal)... *)
389- if Options. debug " data-types-traversal" then
390- KPrint. bprintf " DEFERRING %a\n " ptyp (fold_tapp n);
391- if match def with Union _ -> true | _ -> false then
392- self#record (DType (chosen_lid, flags, 0 , 0 , Forward FUnion ))
393- else
394- self#record (DType (chosen_lid, flags, 0 , 0 , Forward FStruct ));
395- Hashtbl. add pending_monomorphizations lid (args, cgs);
396- (* FORWARD DECLARATIONS: remove us from the state to make sure future occurences of the
397- same situation send us through this codepath again *)
398- Hashtbl. remove state n
399- | flags , Variant branches ->
400- let branches = List. map (fun (cons , fields ) -> cons, subst fields) branches in
401- let branches = self#visit_branches_t under_ref branches in
402- self#record (DType (chosen_lid, flag @ flags, 0 , 0 , Variant branches));
403- Hashtbl. replace state n (Black , chosen_lid)
404- | flags , Flat fields ->
405- let fields = self#visit_fields_t_opt under_ref (subst fields) in
406- self#record (DType (chosen_lid, flag @ flags, 0 , 0 , Flat fields));
407- Hashtbl. replace state n (Black , chosen_lid)
408- | flags , Union fields ->
409- let fields = List. map (fun (f , t ) ->
335+ (* Fast-path:
336+ - there are no type arguments (so: nothing to monomorphize here)
337+ - we are not under a ref (so: no forward declarations to insert here),
338+ - we are not visiting ourselves either (so: no hopeful forward declaration to insert here)
339+ --> we do not visit this lid, and do not self#record it.
340+
341+ 1. If we saw this lid, great.
342+ 2. If we haven't seen this lid yet, no problem, its contents will be
343+ visited through self#visit_decl in the case where n = 0 && n_cgs = 0,
344+ and it will be inserted in its original spot, which has the nice
345+ side-effect of preserving the source order.*)
346+ if snd3 n = [] && thd3 n = [] && not under_ref && Option. map fst @@ Hashtbl. find_opt state n <> Some Gray then
347+ fst3 n
348+ else
349+ (* We recursively visit the arguments. This avoids inconsistencies where
350+ the map would previously record both t<u<v>> and t<u__v> which then
351+ required renormalizations and didn't work anyhow.
352+
353+ Because we have no equirecursive types, this should not loop *)
354+ let n = fst3 n, List. map (self#visit_typ under_ref) (snd3 n), thd3 n in
355+ let lid, args, cgs = n in
356+ (* White, gray or black? *)
357+ match Hashtbl. find state n with
358+ | exception Not_found ->
359+ let chosen_lid, flag = self#lid_of n in
360+ if Options. debug " data-types-traversal" then
361+ KPrint. bprintf " visiting %a: Not_found --> %a\n " ptyp (fold_tapp n) plid chosen_lid;
362+ let flag = if fst3 best_hint = n then thd3 best_hint @ flag else flag in
363+ if lid = tuple_lid then begin
364+ assert (args <> [] );
365+ Hashtbl. add state n (Gray , chosen_lid);
366+ (* For tuples, we immediately know how to generate a definition. *)
367+ let fields = List. mapi (fun i arg -> Some (self#field_at i), (arg, false )) args in
368+ self#record (DType (chosen_lid, [ Common. Private ] @ flag, 0 , 0 , Flat fields));
369+ Hashtbl. replace state n (Black , chosen_lid)
370+ end else begin
371+ (* This specific node has not been visited yet. *)
372+ Hashtbl. add state n (Gray , chosen_lid);
373+
374+ let subst fields = List. map (fun (field , (t , m )) ->
375+ field, (DeBruijn. subst_tn args (DeBruijn. subst_ctn' cgs t), m)
376+ ) fields in
377+ assert (not (Hashtbl. mem map lid) || not (has_variables args) && not (has_cg_variables cgs));
378+ begin match Hashtbl. find map lid with
379+ | exception Not_found ->
380+ (* Unknown, external non-polymorphic lid, e.g. Prims.int *)
381+ Hashtbl. replace state n (Black , chosen_lid)
382+ | flags , ((Variant _ | Flat _ | Union _ ) as def ) when under_ref && not (Hashtbl. mem seen_declarations lid) ->
383+ (* FORWARD DECLARATION: this is unrelated to monomorphization (but we do it
384+ here anyway). An occurrence of `t<ts>*` appears before the definition of `t`; we
385+ pick a name, insert a forward declaration for `t<ts>`, then remember that *once we
386+ have see the definition of `t`, we will insert the monomorphized `t___ts` at that
387+ specific location.
388+
389+ The comment below furthermore tries to explain why we do things this way (as
390+ opposed to inserting the monomorphized `t___ts` immediately).
391+
392+ Because this looks up a definition in the global map, the
393+ definitions are reordered according to the traversal order, which
394+ is generally a good idea (we accept more programs!), EXCEPT
395+ when the user relies on mutual recursion behind a reference
396+ (pointer) type. In that case, following the type dependency graph is
397+ generally not a good idea, since we may go from a valid
398+ ordering to an invalid one (see tests/MutualStruct.fst). So,
399+ the intent here (i.e., when under a ref type) is that:
400+ - tuple types ALWAYS get monomorphized on-demand (see
401+ above)
402+ - abbreviations are fine and won't cause further issues
403+ - data types, however, need to have their names allocated and a
404+ forward reference inserted (TODO: at most once), then the
405+ specific choice of type arguments need to be recorded as
406+ something we want to visit later (once we're done with this
407+ particular traversal)... *)
408+ if Options. debug " data-types-traversal" then
409+ KPrint. bprintf " DEFERRING %a\n " ptyp (fold_tapp n);
410+ if match def with Union _ -> true | _ -> false then
411+ self#record (DType (chosen_lid, flags, 0 , 0 , Forward FUnion ))
412+ else
413+ self#record (DType (chosen_lid, flags, 0 , 0 , Forward FStruct ));
414+ Hashtbl. add pending_monomorphizations lid (args, cgs);
415+ (* FORWARD DECLARATIONS: remove us from the state to make sure future occurences of the
416+ same situation send us through this codepath again *)
417+ Hashtbl. remove state n
418+ | flags , Variant branches ->
419+ let branches = List. map (fun (cons , fields ) -> cons, subst fields) branches in
420+ let branches = self#visit_branches_t under_ref branches in
421+ if args <> [] || cgs <> [] then
422+ self#record (DType (chosen_lid, flag @ flags, 0 , 0 , Variant branches));
423+ Hashtbl. replace state n (Black , chosen_lid)
424+ | flags , Flat fields ->
425+ let fields = self#visit_fields_t_opt under_ref (subst fields) in
426+ if args <> [] || cgs <> [] then
427+ self#record (DType (chosen_lid, flag @ flags, 0 , 0 , Flat fields));
428+ Hashtbl. replace state n (Black , chosen_lid)
429+ | flags , Union fields ->
430+ let fields = List. map (fun (f , t ) ->
431+ let t = DeBruijn. subst_tn args t in
432+ let t = self#visit_typ under_ref t in
433+ f, t
434+ ) fields in
435+ if args <> [] || cgs <> [] then
436+ self#record (DType (chosen_lid, flag @ flags, 0 , 0 , Union fields));
437+ Hashtbl. replace state n (Black , chosen_lid)
438+ | flags , Abbrev t ->
410439 let t = DeBruijn. subst_tn args t in
411440 let t = self#visit_typ under_ref t in
412- f, t
413- ) fields in
414- self#record (DType (chosen_lid, flag @ flags, 0 , 0 , Union fields));
415- Hashtbl. replace state n (Black , chosen_lid)
416- | flags , Abbrev t ->
417- let t = DeBruijn. subst_tn args t in
418- let t = self#visit_typ under_ref t in
419- self#record (DType (chosen_lid, flag @ flags, 0 , 0 , Abbrev t));
420- Hashtbl. replace state n (Black , chosen_lid)
421- | _ ->
422- Hashtbl. replace state n (Black , chosen_lid)
423- end
424- end ;
425- chosen_lid
426- | Gray , chosen_lid ->
427- (* FORWARD DECLARATION: simple case of a recursive type that needs a forward declaration *)
428- if Options. debug " data-types-traversal" then
429- KPrint. bprintf " visiting %a: Gray\n " ptyp (fold_tapp n);
430- begin match Hashtbl. find map lid with
431- | exception Not_found ->
432- ()
433- | flags , Union _ ->
434- self#record (DType (chosen_lid, flags, 0 , 0 , Forward FUnion ))
435- | flags , _ ->
436- self#record (DType (chosen_lid, flags, 0 , 0 , Forward FStruct ))
437- end ;
438- chosen_lid
439- | Black , chosen_lid ->
440- if Options. debug " data-types-traversal" then
441- KPrint. bprintf " visiting %a: Black\n " ptyp (fold_tapp n);
442- chosen_lid
441+ if args <> [] || cgs <> [] then
442+ self#record (DType (chosen_lid, flag @ flags, 0 , 0 , Abbrev t));
443+ Hashtbl. replace state n (Black , chosen_lid)
444+ | _ ->
445+ Hashtbl. replace state n (Black , chosen_lid)
446+ end
447+ end ;
448+ chosen_lid
449+ | Gray , chosen_lid ->
450+ (* FORWARD DECLARATION: simple case of a recursive type that needs a
451+ forward declaration.
452+
453+ We still insert something to deal with cases like
454+
455+ typedef struct s {
456+ void f(t x);
457+ } t;
458+ *)
459+ if Options. debug " data-types-traversal" then
460+ KPrint. bprintf " visiting %a: Gray\n " ptyp (fold_tapp n);
461+ begin match Hashtbl. find map lid with
462+ | exception Not_found ->
463+ ()
464+ | flags , Union _ ->
465+ self#record (DType (chosen_lid, flags, 0 , 0 , Forward FUnion ))
466+ | flags , _ ->
467+ self#record (DType (chosen_lid, flags, 0 , 0 , Forward FStruct ))
468+ end ;
469+ chosen_lid
470+ | Black , chosen_lid ->
471+ if Options. debug " data-types-traversal" then
472+ KPrint. bprintf " visiting %a: Black\n " ptyp (fold_tapp n);
473+ chosen_lid
443474
444475 (* Top-level, non-parameterized declarations are root of our graph traversal.
445476 * This also visits, via occurrences in code, applications of parameterized
@@ -514,18 +545,13 @@ let monomorphize_data_types map = object(self)
514545
515546 | DType (lid , _ , n_cgs , n , (Flat _ | Variant _ | Abbrev _ | Union _ )) ->
516547 assert (n = 0 && n_cgs = 0 );
517- (* Regular traversal logic, as below. *)
518- ignore (self#visit_decl false d);
519- (* FORWARD DECLARATIONS: we force a visit of this (non-polymorphic) type definition, for
520- the sole side-effect of remembering that we have seen it, and that further occurrences
521- of it need not generate a forward declaration (i.e. mark it Black, because
522- under_ref=false).
523-
524- Note that `visit_node` will insert our own definition in the pending list, flushed by
525- `clear` -- ignore and don't insert twice. *)
526- ignore (self#visit_node false (lid, [] , [] ));
548+ (* This was not inserted earlier (see comment at the beginning of
549+ visit_node, so we visit it here *)
550+ Hashtbl. add state (lid, [] , [] ) (Gray , lid);
551+ let d = self#visit_decl false d in
552+ Hashtbl. replace state (lid, [] , [] ) (Black , lid);
527553 Hashtbl. add seen_declarations lid () ;
528- self#clear ()
554+ self#clear () @ [ d ]
529555
530556 | _ ->
531557 (* Not a type, e.g. a global; needs to be retained. *)
0 commit comments