[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