[m-rev.] diff: don't materialise dummy variables in (de)constructions in erlang

Peter Wang wangp at students.csse.unimelb.edu.au
Thu Jun 14 13:52:29 AEST 2007


Estimated hours taken: 1.5
Branches: main

Change the handling of dummy variables in constructions and deconstructions in
the Erlang backend.  In constructions, replace dummy variables in the
constructed term directly by `false'.  In deconstructions, replace dummy
variables by the anonymous variable (_).  These changes save us from
materialising dummy variables in more places which could lead to 'unsafe
variable' errors.

compiler/erl_code_util.m:
	Move the filtering of dummy variables from erl_bind_unbound_vars to
	erl_bound_nonlocals_in_goal.

	Make erl_bound_nonlocals_in_goal take a erl_gen_info argument instead
	of a module_info argument as it now requires the vartypes map as well.

compiler/erl_unify_gen.m:
	Make cons_id_to_term and cons_id_to_expr take an argument, which is
	what to replace any dummy variables with in the term or expression.

compiler/erl_code_gen.m:
	Conform to the changes above.

Index: compiler/erl_code_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/erl_code_gen.m,v
retrieving revision 1.12
diff -u -r1.12 erl_code_gen.m
--- compiler/erl_code_gen.m	14 Jun 2007 01:50:28 -0000	1.12
+++ compiler/erl_code_gen.m	14 Jun 2007 03:49:03 -0000
@@ -433,8 +433,7 @@
 erl_gen_commit_pieces(Goal, InstMap, _Context, DoRenaming,
         GoalStatement, PackedNonLocals, !Info) :-
     % Find the nonlocal variables bound by the goal.
-    erl_gen_info_get_module_info(!.Info, ModuleInfo),
-    erl_bound_nonlocals_in_goal(ModuleInfo, InstMap, Goal, NonLocalsSet),
+    erl_bound_nonlocals_in_goal(!.Info, InstMap, Goal, NonLocalsSet),
     NonLocals = set.to_sorted_list(NonLocalsSet),
 
     % Throw = ``throw({'MERCURY_COMMIT', {NonLocals, ...})''
@@ -616,9 +615,8 @@
     %
 
     % Get the union of all nonlocal variables bound in all cases.
-    erl_gen_info_get_module_info(!.Info, ModuleInfo),
     CasesGoals = list.map((func(case(_, Goal)) = Goal), CasesList),
-    union_bound_nonlocals_in_goals(ModuleInfo, InstMap0, CasesGoals,
+    union_bound_nonlocals_in_goals(!.Info, InstMap0, CasesGoals,
         NonLocalsBoundInCases),
 
     % Create a closure for the success expression if it is too large to
@@ -657,7 +655,7 @@
     erl_gen_info_get_module_info(!.Info, ModuleInfo),
     Size = cons_id_size(ModuleInfo, Type, ConsId),
     erl_gen_info_new_anonymous_vars(Size, DummyVars, !Info),
-    ( cons_id_to_term(ConsId, DummyVars, Pattern0, !Info) ->
+    ( cons_id_to_term(ConsId, DummyVars, elds_anon_var, Pattern0, !Info) ->
         Pattern = Pattern0
     ;
         unexpected(this_file, "erl_gen_case: cannot pattern match on object")
@@ -708,11 +706,11 @@
 %-----------------------------------------------------------------------------%
 % This code is shared by disjunctions and switches.
 
-:- pred union_bound_nonlocals_in_goals(module_info::in, instmap::in,
+:- pred union_bound_nonlocals_in_goals(erl_gen_info::in, instmap::in,
     hlds_goals::in, set(prog_var)::out) is det.
 
-union_bound_nonlocals_in_goals(ModuleInfo, InstMap, Goals, NonLocalsUnion) :-
-    IsBound = erl_bound_nonlocals_in_goal(ModuleInfo, InstMap),
+union_bound_nonlocals_in_goals(Info, InstMap, Goals, NonLocalsUnion) :-
+    IsBound = erl_bound_nonlocals_in_goal(Info, InstMap),
     list.map(IsBound, Goals, NonLocalsLists),
     NonLocalsUnion = set.union_list(NonLocalsLists).
 
@@ -831,10 +829,9 @@
         % Find the non-local variables bound in the condition.
         % The instmap before Then should really be
         % InstMap0 + instmap_delta(Cond) but this is okay.
-        erl_gen_info_get_module_info(!.Info, ModuleInfo),
-        erl_bound_nonlocals_in_goal(ModuleInfo, InstMap0, Cond, CondVars),
-        erl_bound_nonlocals_in_goal(ModuleInfo, InstMap0, Then, ThenVars),
-        erl_bound_nonlocals_in_goal(ModuleInfo, InstMap0, Else, ElseVars),
+        erl_bound_nonlocals_in_goal(!.Info, InstMap0, Cond, CondVars),
+        erl_bound_nonlocals_in_goal(!.Info, InstMap0, Then, ThenVars),
+        erl_bound_nonlocals_in_goal(!.Info, InstMap0, Else, ElseVars),
         CondVarsList = set.to_sorted_list(CondVars),
 
         % Generate the condition goal, making it evaluate to a tuple of the
@@ -1099,9 +1096,7 @@
                 MaybeSuccessExpr, RestStatement, !Info),
 
             % Find the variables bound by First.
-            erl_gen_info_get_module_info(!.Info, ModuleInfo), 
-            erl_bound_nonlocals_in_goal(ModuleInfo, InstMap0, First,
-                NonLocalsSet),
+            erl_bound_nonlocals_in_goal(!.Info, InstMap0, First, NonLocalsSet),
             NonLocals = set.to_sorted_list(NonLocalsSet),
 
             % Make the success continuation.  Rename apart any variables bound
@@ -1163,8 +1158,7 @@
     Rest = [_ | _],
 
     % Get the union of all nonlocal variables bound in all disjuncts.
-    erl_gen_info_get_module_info(!.Info, ModuleInfo),
-    union_bound_nonlocals_in_goals(ModuleInfo, InstMap0, [First | Rest],
+    union_bound_nonlocals_in_goals(!.Info, InstMap0, [First | Rest],
         NonLocalsBoundInGoals),
 
     % Create a closure for the success expression if it is too large to
@@ -1251,9 +1245,7 @@
             % RestStatement end up binding the same variables which triggers a
             % (spurious) warning from the Erlang compiler.
             %
-            erl_gen_info_get_module_info(!.Info, ModuleInfo),
-            erl_bound_nonlocals_in_goal(ModuleInfo, InstMap, First, 
-                FirstVarsSet),
+            erl_bound_nonlocals_in_goal(!.Info, InstMap, First, FirstVarsSet),
             FirstVars = set.to_sorted_list(FirstVarsSet),
             erl_create_renaming(FirstVars, Subn, !Info),
             erl_rename_vars_in_expr(Subn, FirstStatement0, FirstStatement),
@@ -1298,8 +1290,7 @@
         erl_gen_goal(model_non, InstMap, First, MaybeSuccessExprForFirst,
             FirstStatement0, !Info),
 
-        erl_gen_info_get_module_info(!.Info, ModuleInfo),
-        erl_bound_nonlocals_in_goal(ModuleInfo, InstMap, First, FirstVarsSet),
+        erl_bound_nonlocals_in_goal(!.Info, InstMap, First, FirstVarsSet),
         FirstVars = set.to_sorted_list(FirstVarsSet),
         erl_create_renaming(FirstVars, Subst, !Info),
         erl_rename_vars_in_expr(Subst, FirstStatement0, FirstStatement),
Index: compiler/erl_code_util.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/erl_code_util.m,v
retrieving revision 1.7
diff -u -r1.7 erl_code_util.m
--- compiler/erl_code_util.m	14 Jun 2007 01:50:28 -0000	1.7
+++ compiler/erl_code_util.m	14 Jun 2007 03:49:03 -0000
@@ -128,10 +128,10 @@
     maybe(elds_expr)::in, maybe(elds_expr)::out,
     erl_gen_info::in, erl_gen_info::out) is det.
 
-    % Return the set of variables non-local to a goal which are bound
+    % Return the set of non-dummy variables non-local to a goal which are bound
     % by that goal.
     %
-:- pred erl_bound_nonlocals_in_goal(module_info::in, instmap::in,
+:- pred erl_bound_nonlocals_in_goal(erl_gen_info::in, instmap::in,
     hlds_goal::in, set(prog_var)::out) is det.
 
     % erl_bind_unbound_vars(Info, VarsToBind, Goal, InstMap, !Statement)
@@ -144,7 +144,7 @@
     % variables do not matter since this is only done to appease the
     % Erlang compiler.
     %
-    % Variables of dummy types are not bound.
+    % VarsToBind must not include dummy variables.
     %
 :- pred erl_bind_unbound_vars(erl_gen_info::in, set(prog_var)::in,
     hlds_goal::in, instmap::in, elds_expr::in, elds_expr::out) is det.
@@ -375,20 +375,27 @@
 
 %-----------------------------------------------------------------------------%
 
-erl_bound_nonlocals_in_goal(ModuleInfo, InstMap, Goal, BoundNonLocals) :-
+erl_bound_nonlocals_in_goal(Info, InstMap, Goal, BoundNonLocals) :-
+    erl_gen_info_get_module_info(Info, ModuleInfo),
+    erl_gen_info_get_var_types(Info, VarTypes),
     Goal = hlds_goal(_, GoalInfo),
     goal_info_get_nonlocals(GoalInfo, NonLocals),
     goal_info_get_instmap_delta(GoalInfo, InstmapDelta),
-    IsBound = var_is_bound_in_instmap_delta(ModuleInfo, InstMap, InstmapDelta),
-    BoundNonLocals = set.filter(IsBound, NonLocals).
+    BoundNonLocals = set.filter(is_bound_and_not_dummy(ModuleInfo, VarTypes,
+        InstMap, InstmapDelta), NonLocals).
+
+:- pred is_bound_and_not_dummy(module_info::in, vartypes::in, instmap::in,
+    instmap_delta::in, prog_var::in) is semidet.
+
+is_bound_and_not_dummy(ModuleInfo, VarTypes, InstMap, InstmapDelta, Var) :-
+    var_is_bound_in_instmap_delta(ModuleInfo, InstMap, InstmapDelta, Var),
+    map.lookup(VarTypes, Var, Type),
+    not is_dummy_argument_type(ModuleInfo, Type).
 
 erl_bind_unbound_vars(Info, VarsToBind, Goal, InstMap,
         Statement0, Statement) :-
-    erl_gen_info_get_module_info(Info, ModuleInfo),
-    erl_gen_info_get_var_types(Info, VarTypes),
-    erl_bound_nonlocals_in_goal(ModuleInfo, InstMap, Goal, Bound),
-    NotBound0 = set.difference(VarsToBind, Bound),
-    NotBound = set.filter(non_dummy_var(ModuleInfo, VarTypes), NotBound0),
+    erl_bound_nonlocals_in_goal(Info, InstMap, Goal, Bound),
+    NotBound = set.difference(VarsToBind, Bound),
     (if set.empty(NotBound) then
         Statement = Statement0
     else
@@ -398,12 +405,6 @@
         Statement = join_exprs(elds_block(Assignments), Statement0)
     ).
 
-:- pred non_dummy_var(module_info::in, vartypes::in, prog_var::in) is semidet.
-
-non_dummy_var(ModuleInfo, VarTypes, Var) :-
-    map.lookup(VarTypes, Var, Type),
-    not is_dummy_argument_type(ModuleInfo, Type).
-
 %-----------------------------------------------------------------------------%
 
 erl_create_renaming(Vars, Subst, !Info) :-
Index: compiler/erl_unify_gen.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/erl_unify_gen.m,v
retrieving revision 1.6
diff -u -r1.6 erl_unify_gen.m
--- compiler/erl_unify_gen.m	4 Jun 2007 07:46:09 -0000	1.6
+++ compiler/erl_unify_gen.m	14 Jun 2007 03:49:03 -0000
@@ -54,10 +54,10 @@
     % returned by this predicate must be useable as part of a pattern matching
     % operation.
     %
-:- pred cons_id_to_term(cons_id, prog_vars, elds_term,
+:- pred cons_id_to_term(cons_id, prog_vars, elds_term, elds_term,
     erl_gen_info, erl_gen_info).
-:- mode cons_id_to_term(in, in, out, in, out) is semidet.
-:- mode cons_id_to_term(in(termable_cons_id), in, out, in, out) is det.
+:- mode cons_id_to_term(in, in, in, out, in, out) is semidet.
+:- mode cons_id_to_term(in(termable_cons_id), in, in, out, in, out) is det.
 
 :- inst termable_cons_id
     --->    cons(ground, ground)
@@ -67,8 +67,8 @@
 
     % Convert a cons id to the ELDS equivalent expression.
     %
-:- pred cons_id_to_expr(cons_id::in, prog_vars::in, elds_expr::out,
-    erl_gen_info::in, erl_gen_info::out) is det.
+:- pred cons_id_to_expr(cons_id::in, prog_vars::in, elds_term::in,
+    elds_expr::out, erl_gen_info::in, erl_gen_info::out) is det.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
@@ -88,6 +88,7 @@
 
 :- import_module int.
 :- import_module list.
+:- import_module map.
 :- import_module pair.
 :- import_module set.
 :- import_module string.
@@ -173,7 +174,7 @@
 
 erl_gen_construct(Var, ConsId, Args, ArgTypes, UniModes, _Context, Statement,
         !Info) :-
-    cons_id_to_expr(ConsId, Args, RHS, !Info),
+    cons_id_to_expr(ConsId, Args, elds_false, RHS, !Info),
     Construct = elds_eq(expr_from_var(Var), RHS),
     %
     % If there are any free variables in Args, assign them to false first.
@@ -210,7 +211,7 @@
 
 erl_gen_det_deconstruct(Var, ConsId, Args, _Modes, _Context, Statement,
         !Info) :-
-    cons_id_to_expr(ConsId, Args, LHS, !Info),
+    cons_id_to_expr(ConsId, Args, elds_anon_var, LHS, !Info),
     Statement = elds_eq(LHS, expr_from_var(Var)).
 
 :- pred erl_gen_semidet_deconstruct(prog_var::in, cons_id::in, prog_vars::in,
@@ -219,7 +220,7 @@
 
 erl_gen_semidet_deconstruct(Var, ConsId, Args, _Modes, _Context,
         SuccessExpr, Statement, !Info) :-
-    ( cons_id_to_term(ConsId, Args, Pattern0, !Info) ->
+    ( cons_id_to_term(ConsId, Args, elds_anon_var, Pattern0, !Info) ->
         Pattern = Pattern0
     ;
         unexpected(this_file,
@@ -237,7 +238,7 @@
 
 %-----------------------------------------------------------------------------%
 
-cons_id_to_term(ConsId, Args, Term, !Info) :-
+cons_id_to_term(ConsId, Args, DummyVarReplacement, Term, !Info) :-
     (
         ConsId = cons(Name, _Arity),
         (
@@ -249,7 +250,16 @@
             % XXX optimise the cases where we don't actually need a
             % distinguishing atom.
             Functor = elds_term(elds_atom(Name)),
-            Term = elds_tuple([Functor | exprs_from_vars(Args)])
+            erl_gen_info_get_module_info(!.Info, ModuleInfo),
+            erl_gen_info_get_var_types(!.Info, VarTypes),
+
+            % Replace dummy variables in the term.  In construction
+            % unifications we would want to replace them with `false' (what
+            % we use for all dummy values).  In deconstructions we replace
+            % them by anonymous variables (_).
+            TermArgs = list.map(var_or_dummy_replacement(ModuleInfo, VarTypes,
+                DummyVarReplacement), Args),
+            Term = elds_tuple([Functor | TermArgs])
         )
     ;
         ConsId = int_const(Int),
@@ -262,14 +272,27 @@
         Term = elds_float(Float)
     ).
 
-cons_id_to_expr(ConsId, Args, Expr, !Info) :-
+:- func var_or_dummy_replacement(module_info, vartypes, elds_term, prog_var) =
+    elds_expr.
+
+var_or_dummy_replacement(ModuleInfo, VarTypes, DummyVarReplacement, Var) =
+    (if
+        map.search(VarTypes, Var, Type),
+        is_dummy_argument_type(ModuleInfo, Type)
+    then
+        elds_term(DummyVarReplacement)
+    else
+        expr_from_var(Var)
+    ).
+
+cons_id_to_expr(ConsId, Args, DummyVarReplacement, Expr, !Info) :-
     (
         ( ConsId = cons(_, _)
         ; ConsId = int_const(_)
         ; ConsId = string_const(_)
         ; ConsId = float_const(_)
         ),
-        cons_id_to_term(ConsId, Args, Term, !Info),
+        cons_id_to_term(ConsId, Args, DummyVarReplacement, Term, !Info),
         Expr = elds_term(Term)
     ;
         ConsId = pred_const(ShroudedPredProcId, lambda_normal),
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list