Skip to content

Commit 40c4705

Browse files
authored
Ensure consistent variable binding times (#3217)
When joining environments, we exclude variables that are no longer useful in the joined environment. This causes the remaining variables to have new (lower) binding times. If we later join the resulting environment again with another environment that still has those variables, we end up having the same variable with different binding times in the joined level, and we define the variable twice in the resulting environment. This can allow breaking the order between two variable's binding times, which means that different canonical elements can be chosen in different environments for the same pair of variables. This patch fixes the issue by keeping track of `next_binding_time` *globally* across all related environments and keeping the binding time during join, ensuring that the binding time of a variable is globally unique and preventing any such re-orderings. Longer explanation ------------------ Consider 4 environments that define variables `a`, `b`, `c`, and `d`. ``` _________________________________ / | | \ Env 1 Env 2 Env 3 Env 4 / | | \ define a define a define a define a | | | | define b define b define b define b | | | | define c define c define c define c | | | | define d define d define d define d ``` Suppose that we first join environments 3 and 4 (filtering out `a` and `b`) and environments 1 and 2 (filtering out `d`): ``` ____________ / \ Env 1 \/ 2 Env 3 \/ 4 / \ define a define c | | define b define d | define c ``` Once we join the two resulting environments, if we filter out `a` and `b` but keep `c` and `d`, the current implementation creates a level which defines `c`, then `d`, then `c` again. Since we keep the last definition, we end up with the environment: ``` define d | define c ``` We have now swapped the binding times of `c` and `d` which, if they were in the same alias set, can introduce subtle bugs.
1 parent 9a43d33 commit 40c4705

File tree

3 files changed

+30
-20
lines changed

3 files changed

+30
-20
lines changed

middle_end/flambda2/types/env/typing_env.ml

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ type t =
113113
(* [prev_levels] is sorted with the greatest scope at the head of the
114114
list *)
115115
current_level : One_level.t;
116-
next_binding_time : Binding_time.t;
116+
next_binding_time : Binding_time.t ref;
117+
(* [next_binding_time] is a reference shared by all related environments to
118+
the latest binding time ever used. Used to ensure consistent binding
119+
times between variables defined in parallel branches. *)
117120
min_binding_time : Binding_time.t;
118121
(* Earlier variables have mode In_types *)
119122
is_bottom : bool
@@ -385,7 +388,7 @@ let create ~resolver ~get_imported_names =
385388
to allow an efficient implementation of [cut] (see below), we always
386389
increment the scope by one here. *)
387390
current_level = One_level.create_empty (Scope.next Scope.initial);
388-
next_binding_time = Binding_time.earliest_var;
391+
next_binding_time = ref Binding_time.earliest_var;
389392
defined_symbols = Symbol.Set.empty;
390393
code_age_relation = Code_age_relation.empty;
391394
min_binding_time = Binding_time.earliest_var;
@@ -620,17 +623,14 @@ let alias_is_bound_strictly_earlier t ~bound_name ~alias =
620623

621624
let with_current_level t ~current_level = { t with current_level }
622625

623-
let with_current_level_and_next_binding_time t ~current_level next_binding_time
624-
=
625-
{ t with current_level; next_binding_time }
626-
627626
let with_aliases t ~aliases =
628627
let current_level = One_level.with_aliases t.current_level ~aliases in
629628
with_current_level t ~current_level
630629

631630
let cached t = One_level.just_after_level t.current_level
632631

633-
let add_variable_definition t var kind name_mode =
632+
let add_variable_definition_with_binding_time ~binding_time t var kind name_mode
633+
=
634634
(* We can add equations in our own compilation unit on variables and symbols
635635
defined in another compilation unit. However we can't define other
636636
compilation units' variables or symbols (except for predefined symbols such
@@ -644,24 +644,28 @@ let add_variable_definition t var kind name_mode =
644644
%a@ in environment:@ %a"
645645
Variable.print var print t;
646646
let name = Name.var var in
647-
if Flambda_features.check_invariants () && mem t name
647+
if Flambda_features.check_light_invariants () && mem t name
648648
then
649649
Misc.fatal_errorf "Cannot rebind %a in environment:@ %a" Name.print name
650650
print t;
651651
let level =
652-
TEL.add_definition
653-
(One_level.level t.current_level)
654-
var kind t.next_binding_time
652+
TEL.add_definition (One_level.level t.current_level) var kind binding_time
655653
in
656654
let just_after_level =
657655
Cached_level.add_or_replace_binding (cached t) name (MTC.unknown kind)
658-
t.next_binding_time name_mode
656+
binding_time name_mode
659657
in
660658
let current_level =
661659
One_level.create (current_scope t) level ~just_after_level
662660
in
663-
with_current_level_and_next_binding_time t ~current_level
664-
(Binding_time.succ t.next_binding_time)
661+
with_current_level t ~current_level
662+
663+
let get_next_binding_time t = !(t.next_binding_time)
664+
665+
let add_variable_definition t var kind name_mode =
666+
let binding_time = get_next_binding_time t in
667+
t.next_binding_time := Binding_time.succ binding_time;
668+
add_variable_definition_with_binding_time ~binding_time t var kind name_mode
665669

666670
let add_symbol_definition t sym =
667671
(* CR-someday mshinwell: check for redefinition when invariants enabled? *)
@@ -958,7 +962,9 @@ and add_env_extension_with_extra_variables t
958962
let add_env_extension_from_level t level ~meet_type : t =
959963
let t =
960964
TEL.fold_on_defined_vars
961-
(fun var kind t -> add_variable_definition t var kind Name_mode.in_types)
965+
(fun ~binding_time var kind t ->
966+
add_variable_definition_with_binding_time ~binding_time t var kind
967+
Name_mode.in_types)
962968
level t
963969
in
964970
let t =
@@ -1194,7 +1200,7 @@ let compute_joined_aliases base_env alias_candidates envs_at_uses =
11941200
with_aliases base_env ~aliases:new_aliases
11951201

11961202
let closure_env t =
1197-
increment_scope { t with min_binding_time = t.next_binding_time }
1203+
increment_scope { t with min_binding_time = get_next_binding_time t }
11981204

11991205
let rec free_names_transitive_of_type_of_name t name ~result =
12001206
let result = Name_occurrences.add_name result name Name_mode.in_types in

middle_end/flambda2/types/env/typing_env_level.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ let [@ocamlformat "disable"] print ppf
6969

7070
let fold_on_defined_vars f t init =
7171
Binding_time.Map.fold
72-
(fun _bt vars acc ->
72+
(fun bt vars acc ->
7373
Variable.Set.fold
7474
(fun var acc ->
7575
let kind = Variable.Map.find var t.defined_vars in
76-
f var kind acc)
76+
f ~binding_time:bt var kind acc)
7777
vars acc)
7878
t.binding_times init
7979

@@ -113,7 +113,8 @@ let add_symbol_projection t var proj =
113113
{ t with symbol_projections }
114114

115115
let add_definition t var kind binding_time =
116-
if Flambda_features.check_invariants () && Variable.Map.mem var t.defined_vars
116+
if Flambda_features.check_light_invariants ()
117+
&& Variable.Map.mem var t.defined_vars
117118
then
118119
Misc.fatal_errorf "Environment extension already binds variable %a:@ %a"
119120
Variable.print var print t;

middle_end/flambda2/types/env/typing_env_level.mli

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ val variables_by_binding_time : t -> Variable.Set.t Binding_time.Map.t
5858
val variable_is_defined : t -> Variable.t -> bool
5959

6060
val fold_on_defined_vars :
61-
(Variable.t -> Flambda_kind.t -> 'a -> 'a) -> t -> 'a -> 'a
61+
(binding_time:Binding_time.t -> Variable.t -> Flambda_kind.t -> 'a -> 'a) ->
62+
t ->
63+
'a ->
64+
'a
6265

6366
val as_extension_without_bindings : t -> Type_grammar.Env_extension.t

0 commit comments

Comments
 (0)