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