[m-rev.] diff: fix bad indirect reuse (again)

Peter Wang novalazy at gmail.com
Wed Apr 23 15:27:56 AEST 2008


Branches: main

Revert my previous change to avoid making some bad indirect reuse calls,
which supposed that the verification of calls to reuse procedures was wrong.
It seems to be correct, as far as it goes.

There were actually a few separate problems elsewhere:

1. `reuse_conditions_add_condition' didn't add a condition to a set if the
set already contains another condition which subsumes it.  However, the
problem in the `bad_indirect_reuse' test case was due to discarding such a
condition, making the reuse conditions on a reuse procedure too weak.  For
now, keep all non-duplicate reuse conditions so this doesn't happen.

2. `livedata_init_at_goal' was missing quite a lot of code that was in the
old reuse branch, so the set of known live data at each call site was too
small.  Port over the missing code from the reuse branch.  This fixes the
`bad_indirect_reuse2' test case.

3. Although a call might satisfy all the reuse conditions of the callee
individually, we weren't checking that two input arguments didn't have
sharing between them.  Port over code from the old reuse branch to check
this.  This fixes the `bad_indirect_reuse3' test case.


compiler/ctgc.livedata.m:
	Fix problem 2.

	Revert my previous change.

compiler/structure_reuse.domain.m:
	Work around problem 1.

	Fix problem 3.

compiler/structure_reuse.indirect.m:
compiler/structure_sharing.domain.m:
	Revert my previous change.

compiler/ctgc.datastruct.m:
	Add a utility predicate.

tests/hard_coded/Mercury.options:
tests/hard_coded/Mmakefile:
tests/hard_coded/bad_indirect_reuse2b.exp:
tests/hard_coded/bad_indirect_reuse2b.m:
	Add a simpler version of bad_indirect_reuse2.

Index: compiler/ctgc.datastruct.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ctgc.datastruct.m,v
retrieving revision 1.10
diff -u -r1.10 ctgc.datastruct.m
--- compiler/ctgc.datastruct.m	10 Jan 2008 04:29:51 -0000	1.10
+++ compiler/ctgc.datastruct.m	23 Apr 2008 03:20:04 -0000
@@ -35,6 +35,11 @@
     %
 :- pred datastruct_equal(datastruct::in, datastruct::in) is semidet.
 
+    % Check whether the two given datastructs are related to the
+    % same variable or not. 
+    %
+:- pred datastruct_same_vars(datastruct::in, datastruct::in) is semidet.
+
     % Verify whether the datastructure represents a top cell, i.e. where
     % the selector path is an empty path.
     %
@@ -102,6 +107,9 @@
 
 datastruct_equal(D1, D2) :- D1 = D2.
 
+datastruct_same_vars(D1, D2) :-
+    D1 ^ sc_var = D2 ^ sc_var.
+
 datastruct_refers_to_topcell(Data):-
     DSel = Data ^ sc_selector,
     DSel = [].
Index: compiler/ctgc.livedata.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/ctgc.livedata.m,v
retrieving revision 1.4
diff -u -r1.4 ctgc.livedata.m
--- compiler/ctgc.livedata.m	21 Apr 2008 05:15:30 -0000	1.4
+++ compiler/ctgc.livedata.m	23 Apr 2008 03:20:04 -0000
@@ -71,10 +71,11 @@
 
 :- func livedata_init_at_goal(module_info, proc_info, hlds_goal_info,
     sharing_as) = livedata.
+
 :- func livedata_add_liveness(module_info, proc_info, live_datastructs,
     sharing_as, livedata) = livedata.
 
-:- pred nodes_are_not_live(module_info::in, proc_info::in, sharing_as::in,
+:- pred nodes_are_not_live(module_info::in, proc_info::in, 
     list(datastruct)::in, livedata::in) is semidet.
 
 %-----------------------------------------------------------------------------%
@@ -85,6 +86,7 @@
 :- import_module libs.compiler_util.
 :- import_module transform_hlds.ctgc.datastruct.
 
+:- import_module pair.
 :- import_module set.
 
 %-----------------------------------------------------------------------------%
@@ -228,25 +230,114 @@
     -> 
         LiveData = livedata_init_from_vars(Lu)
     ;
-        % otherwise we have the most general case: Lu not empty, Sharing
+        % Otherwise we have the most general case: Lu not empty, Sharing
         % not top nor bottom.
-        LiveData = livedata_init_at_goal_2(ModuleInfo, ProcInfo, Lu, 
-            SharingAs)
+        SharingDomain = to_structure_sharing_domain(SharingAs),
+        (
+            SharingDomain = structure_sharing_real(SharingPairs),
+            LiveData = livedata_init_at_goal_2(ModuleInfo, ProcInfo, Lu,
+                SharingPairs)
+        ;
+            ( SharingDomain = structure_sharing_bottom
+            ; SharingDomain = structure_sharing_top(_)
+            ),
+            unexpected(this_file, "livedata_init_at_goal")
+        )
     ).
 
     % Preconditions: live_vars is not empty, sharing_as is not top.
     %
+    % This function corresponds to pa_alias_as.live_2 in the old reuse branch
+    % which is significantly more involved so there may still be more code to
+    % port over.  However, its caller always passes the empty set for the
+    % LIVE_0 argument which would make a lot of code unnecessary.
+    %
 :- func livedata_init_at_goal_2(module_info, proc_info, live_vars, 
-    sharing_as) = livedata.
+    structure_sharing) = livedata.
+
+livedata_init_at_goal_2(ModuleInfo, ProcInfo, Lu, SharingPairs) = LiveData :-
+    % LIVE1 = top-level datastructs from Lu
+    LuData = list.map(datastruct_init, Lu),
+    LIVE1 = LuData,
+
+    % LIVE2 = datastructs X^s such that X^s is aliased to Y^t,
+    % and Y is in Lu.
+    live_from_in_use(ModuleInfo, ProcInfo, LuData, SharingPairs, LIVE2),
 
-livedata_init_at_goal_2(ModuleInfo, ProcInfo, Lu, SharingAs) = LiveData :-
-    % Let Data0 be the set of data structures pointed at by the 
-    % set of live vars Lu, then LiveData is the result of "extending" 
-    % (Cf. structure_sharing.domain.m) each of the data structures in Data0.
-    Data0 = list.map(datastruct_init, Lu),
-    DataList = extend_datastructs(ModuleInfo, ProcInfo, SharingAs, 
-        Data0), 
-    LiveData = livedata_live(DataList).
+    % LIVE3 was some complicated thing.
+    % But since LIVE_0 is the empty set LIVE3 would be empty too.
+
+    LiveData = livedata_live(LIVE1 ++ LIVE2).
+
+    % In use information is stored as a set of datastructures. This
+    % procedure computes the set of live datastructure using the in-use set
+    % and extending it wrt the sharing information.
+    %
+:- pred live_from_in_use(module_info::in, proc_info::in, list(datastruct)::in,
+    structure_sharing::in, list(datastruct)::out) is det.
+
+live_from_in_use(ModuleInfo, ProcInfo, InUseList, SharingPairs, Live):-
+    % Filter the list of sharing pairs, keeping only the ones that 
+    % involve at least one variable from the IN_USE (LU) set.
+    list.map(one_of_vars_is_live(ModuleInfo, ProcInfo, InUseList),
+        SharingPairs, DatastructsLists),
+    list.condense(DatastructsLists, Live).
+
+	% one_of_vars_is_live(LIST, ALIAS, X^sx1)
+	% returns true if
+	% 	ALIAS = X^sx - Y^sy
+	%   and Y^s1 \in LIST and
+	%		sy = s1.s2 => sx1 = sx
+	% 	   or
+	%		sy.s2 = s1 => sx1 = sx.s2
+    %
+:- pred one_of_vars_is_live(module_info::in, proc_info::in, 
+    list(datastruct)::in, structure_sharing_pair::in, list(datastruct)::out)
+    is det.
+
+one_of_vars_is_live(ModuleInfo, ProcInfo, Datastructs0, PairXY,
+        Datastructs) :- 
+	one_of_vars_is_live_ordered(ModuleInfo, ProcInfo, Datastructs0,
+        PairXY, L1),
+	% Switch order.
+    PairXY = X - Y,
+    PairYX = Y - X,
+	one_of_vars_is_live_ordered(ModuleInfo, ProcInfo, Datastructs0,
+        PairYX, L2),
+    Datastructs = L1 ++ L2.
+
+:- pred one_of_vars_is_live_ordered(module_info::in, proc_info::in,
+	list(datastruct)::in, structure_sharing_pair::in,
+    list(datastruct)::out) is det.
+
+one_of_vars_is_live_ordered(ModuleInfo, ProcInfo, List, Pair, List_Xsx1) :- 
+	Pair = Xsx - Ysy,
+	list.filter(datastruct_same_vars(Ysy), List, Y_List),
+	(
+		% First try to find one of the found datastructs which is 
+		% fully alive: so that Ysy is less or equal to at least one
+		% Ys1 in Y_List (sy = s1.s2)
+		list.filter(datastruct_subsumed_by(ModuleInfo, ProcInfo, Ysy),
+            Y_List, FY_List),
+		FY_List = [_ | _]
+	->
+		Xsx1 = Xsx,
+		List_Xsx1 = [Xsx1]
+	;
+		% Find all datastructs from Y_List which are less or 
+		% equal to Ysy. Select the one with the shortest selector
+		% (Note that there should be only one solution. If more
+		% than one such datastruct is found, the initial live set
+		% is not minimal, while this should be somehow guaranteed).
+		list.filter_map(
+            datastruct_subsumed_by_return_selector(ModuleInfo, ProcInfo, Ysy),
+            Y_List, SelectorList),
+		% Each sx1 = sx.s2, where s2 is one of SelectorList.
+		list.map(
+            (pred(S2::in, Xsx1::out) is det :-
+                datastruct_termshift(S2, Xsx, Xsx1)
+            ), SelectorList, List_Xsx1)
+	).
 
 livedata_add_liveness(ModuleInfo, ProcInfo, LuData, LocalSharing, LiveData0) 
         = LiveData :- 
@@ -261,9 +352,9 @@
             LiveData0, livedata_init_from_datastructs(LuData))
     ;
         % most general case: normal sharing.
-        LuLiveData = livedata_init_from_datastructs(
-            extend_datastructs(ModuleInfo, ProcInfo, 
-                LocalSharing, LuData)),
+        ExtendLuData = extend_datastructs(ModuleInfo, ProcInfo,
+            LocalSharing, LuData),
+        LuLiveData = livedata_init_from_datastructs(ExtendLuData),
         ExtendLiveData = extend_livedata(ModuleInfo, ProcInfo, 
             LocalSharing, LiveData0),
         LiveData = livedata_least_upper_bound(ModuleInfo, ProcInfo, 
@@ -286,7 +377,7 @@
             SharingAs, Data0))
     ).
 
-nodes_are_not_live(ModuleInfo, ProcInfo, SharingAs, DeadNodes, LiveData) :- 
+nodes_are_not_live(ModuleInfo, ProcInfo, Nodes, LiveData) :- 
     (
         LiveData = livedata_top,
         fail
@@ -294,9 +385,8 @@
         LiveData = livedata_bottom,
         true
     ;
-        LiveData = livedata_live(LiveDatastructs),
-        no_node_or_shared_subsumed_by_list(ModuleInfo, ProcInfo, SharingAs,
-            DeadNodes, LiveDatastructs)
+        LiveData = livedata_live(Data),
+        \+ datastructs_subsumed_by_list(ModuleInfo, ProcInfo, Nodes, Data)
     ).
 
 %-----------------------------------------------------------------------------%
Index: compiler/structure_reuse.domain.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.domain.m,v
retrieving revision 1.12
diff -u -r1.12 structure_reuse.domain.m
--- compiler/structure_reuse.domain.m	21 Apr 2008 05:15:30 -0000	1.12
+++ compiler/structure_reuse.domain.m	23 Apr 2008 03:20:04 -0000
@@ -58,6 +58,9 @@
 
 :- pred reuse_condition_is_conditional(reuse_condition::in) is semidet.
 
+:- pred reuse_condition_reusable_nodes(reuse_condition::in,
+    dead_datastructs::out) is semidet.
+
     % Renaming operation. 
     % This operation renames all occurrences of program variables and
     % type variables according to a program and type variable mapping.
@@ -301,6 +304,8 @@
 
 reuse_condition_is_conditional(condition(_, _, _)).
 
+reuse_condition_reusable_nodes(condition(Nodes, _, _), Nodes).
+
 reuse_condition_subsumed_by(ModuleInfo, ProcInfo, Cond1, Cond2) :- 
     (   
         Cond1 = always
@@ -450,11 +455,13 @@
 :- pred reuse_conditions_add_condition(module_info::in, proc_info::in,
     reuse_condition::in, reuse_conditions::in, reuse_conditions::out) is det.
 
-reuse_conditions_add_condition(ModuleInfo, ProcInfo, Condition, !Conds):- 
+reuse_conditions_add_condition(_ModuleInfo, _ProcInfo, Condition, !Conds):- 
     (
-        reuse_condition_subsumed_by_list(ModuleInfo, ProcInfo, 
-            Condition, !.Conds)
-    -> 
+        % XXX this used to check if Condition was subsumed by !.Conds, but
+        % that can produce conditions which are too weak, I think.
+        % The test suite has an example of this. --pw
+        list.member(Condition, !.Conds)
+    ->
         true
     ;
         !:Conds = [Condition | !.Conds]
@@ -580,11 +587,75 @@
     ; 
         ReuseAs = conditional(Conditions),
         list.all_true(reuse_condition_satisfied(ModuleInfo, ProcInfo, 
-            LiveData, SharingAs, StaticVars), Conditions)
-            % XXX something about reuse conditions pointing to the
-            % same datastructure to be reused... 
+            LiveData, SharingAs, StaticVars), Conditions),
+
+        % Next to verifying each condition separately, one has to verify
+        % whether the nodes which are reused in each of the conditions are
+        % not aliased within the current context. If this would be the
+        % case, then reuse is not allowed. If this would be allowed, then
+        % the callee want to reuse the different parts of the input while
+        % these may point to exactly the same structure, resulting in
+        % undefined behaviour.
+        no_aliases_between_reuse_nodes(ModuleInfo, ProcInfo, SharingAs,
+            Conditions)
+    ).
+
+:- pred no_aliases_between_reuse_nodes(module_info::in, proc_info::in,
+    sharing_as::in, list(reuse_condition)::in) is semidet.
+
+no_aliases_between_reuse_nodes(ModuleInfo, ProcInfo, SharingAs, Conditions):-
+    list.filter_map(reuse_condition_reusable_nodes, Conditions, ListNodes),
+    list.condense(ListNodes, AllNodes),
+    (
+        AllNodes = [Node | Rest],
+        no_aliases_between_reuse_nodes_2(ModuleInfo, ProcInfo, SharingAs,
+            Node, Rest)
+    ;
+        AllNodes = [],
+        unexpected(this_file, "no_aliases_between_reuse_nodes: no nodes")
+    ).
+
+:- pred no_aliases_between_reuse_nodes_2(module_info::in, proc_info::in,
+    sharing_as::in, datastruct::in, list(datastruct)::in) is semidet.
+
+no_aliases_between_reuse_nodes_2(ModuleInfo, ProcInfo, SharingAs, Node,
+        OtherNodes):-
+    SharingNodes0 = extend_datastruct(ModuleInfo, ProcInfo, SharingAs, Node),
+    list.delete(SharingNodes0, Node, SharingNodes),
+
+    % Check whether none of the structures to which the current Node is
+    % aliased is subsumed by or subsumes one of the other nodes, including the
+    % current node itself.
+    all [SharingNode] (
+        list.member(SharingNode, SharingNodes)
+    =>
+        not there_is_a_subsumption_relation(ModuleInfo, ProcInfo,
+            [Node | OtherNodes], SharingNode)
+    ),
+    (
+        OtherNodes = [NextNode | NextOtherNodes],
+        no_aliases_between_reuse_nodes_2(ModuleInfo, ProcInfo, SharingAs,
+            NextNode, NextOtherNodes)
+    ;
+        OtherNodes = []
     ).
 
+    % Succeed if Data is subsumed or subsumes some of the datastructures in
+    % Datastructs.
+    %
+:- pred there_is_a_subsumption_relation(module_info::in, proc_info::in,
+    list(datastruct)::in, datastruct::in) is semidet.
+
+there_is_a_subsumption_relation(ModuleInfo, ProcInfo, Datastructs, DataA):-
+    list.member(DataB, Datastructs),
+    (
+        datastruct_subsumed_by(ModuleInfo, ProcInfo, DataA, DataB)
+    ;
+        datastruct_subsumed_by(ModuleInfo, ProcInfo, DataB, DataA)
+    ).
+
+%-----------------------------------------------------------------------------%
+
 :- pred reuse_condition_satisfied(module_info::in, proc_info::in,
     livedata::in, sharing_as::in, prog_vars::in, reuse_condition::in) 
     is semidet.
@@ -607,7 +678,7 @@
             SharingAs),
         UpdatedLiveData = livedata_add_liveness(ModuleInfo, ProcInfo, 
             InUseNodes, NewSharing, LiveData),
-        nodes_are_not_live(ModuleInfo, ProcInfo, NewSharing, DeadNodes,
+        nodes_are_not_live(ModuleInfo, ProcInfo, DeadNodes,
             UpdatedLiveData)
     ).
     
Index: compiler/structure_reuse.indirect.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_reuse.indirect.m,v
retrieving revision 1.20
diff -u -r1.20 structure_reuse.indirect.m
--- compiler/structure_reuse.indirect.m	21 Apr 2008 05:15:30 -0000	1.20
+++ compiler/structure_reuse.indirect.m	23 Apr 2008 03:20:04 -0000
@@ -576,16 +576,7 @@
         FormalReuseAs, ActualReuseAs),
     LiveData = livedata_init_at_goal(ModuleInfo, ProcInfo, GoalInfo,
         SharingAs),
-
-    % Nancy's implementation:
-    % ProjectedLiveData = livedata_project(CalleeArgs, LiveData),
-    %
-    % However, that doesn't seem right.  Live data which are not arguments of
-    % the call may be affected by reuse if they share memory with CalleeArgs.
-    % In any case, the implementation of no_node_or_shared_subsumed_by_list
-    % expects live data not to be projected away. --pw
-    ProjectedLiveData = LiveData,
-
+    ProjectedLiveData = livedata_project(CalleeArgs, LiveData),
     StaticVars = set.to_sorted_list(AnalysisInfo ^ static_vars),
     (
         reuse_as_satisfied(ModuleInfo, ProcInfo, ProjectedLiveData,
Index: compiler/structure_sharing.domain.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/structure_sharing.domain.m,v
retrieving revision 1.30
diff -u -r1.30 structure_sharing.domain.m
--- compiler/structure_sharing.domain.m	21 Apr 2008 05:15:30 -0000	1.30
+++ compiler/structure_sharing.domain.m	23 Apr 2008 03:20:04 -0000
@@ -188,15 +188,6 @@
 :- func extend_datastructs(module_info, proc_info, sharing_as, 
     list(datastruct)) = list(datastruct).
 
-    % no_node_or_shared_subsumed_by_list(ModuleInfo, ProcInfo, SharingAs
-    %   Dead, Live)
-    %
-    % Succeed iff none of the Dead datastructures, or memory which shares
-    % with those datastructures, are subsumed by some Live datastructure.
-    %
-:- pred no_node_or_shared_subsumed_by_list(module_info::in, proc_info::in,
-    sharing_as::in, dead_datastructs::in, live_datastructs::in) is semidet.
-
     % apply_widening(ModuleInfo, ProcInfo, WideningLimit, WideningDone,
     %   SharingIn, SharingOut):
     %
@@ -745,58 +736,6 @@
         datastruct_lists_least_upper_bound(ModuleInfo, ProcInfo), 
         DataLists, []).
 
-no_node_or_shared_subsumed_by_list(ModuleInfo, ProcInfo, SharingAs,
-        DeadDatastructs, LiveDatastructs) :-
-    (
-        SharingAs = sharing_as_bottom,
-        not datastructs_subsumed_by_list(ModuleInfo, ProcInfo,
-            DeadDatastructs, LiveDatastructs)
-    ;
-        SharingAs = sharing_as_real_as(sharing_set(_, SharingMap)),
-        not some_node_or_shared_subsumed_by_list(ModuleInfo, ProcInfo,
-            SharingMap, DeadDatastructs, LiveDatastructs)
-    ;
-        SharingAs = sharing_as_top(_),
-        unexpected(this_file,
-            "no_node_or_shared_subsumed_by_list: sharing_as_top")
-    ).
-
-:- pred some_node_or_shared_subsumed_by_list(module_info::in, proc_info::in,
-    map(prog_var, selector_sharing_set)::in, dead_datastructs::in,
-    live_datastructs::in) is semidet.
-
-some_node_or_shared_subsumed_by_list(ModuleInfo, ProcInfo, SharingMap,
-        DeadDatastructs, LiveDatastructs) :-
-    % For each dead cell.
-    list.member(selected_cel(DeadVar, DeadSel), DeadDatastructs),
-    proc_info_get_vartypes(ProcInfo, VarTypes),
-    map.lookup(VarTypes, DeadVar, DeadVarType),
-
-    map.search(SharingMap, DeadVar, SelectorSharingSet),
-    SelectorSharingSet = selector_sharing_set(_, SelectorSharingMap),
-
-    % For some selector Sel such that Sel = DeadSel.Extension, check if some
-    % of the data structures which share with the dead datastructure are
-    % subsumed by live datastructures (which would be bad).
-    %
-    % Note that "extending" the dead datastructure and checking if the
-    % extension is subsumed by live datastructures doesn't work.  If a dead
-    % datastructure `cel(DV, [])' shares with `cel(V, [termsel(...)])' then
-    % the latter won't be included in the extension because the selector
-    % `[termsel(...)]' doesn't subsume `[]'. I don't know if the behaviour of
-    % `selector_sharing_set_extend_datastruct_2' is correct, but my attempts
-    % to change it resulted in breakages elsewhere. --pw
-    %
-    map.member(SelectorSharingMap, Sel, SelDataSet),
-    ( selector.subsumed_by(ModuleInfo, Sel, DeadSel, DeadVarType, _) ->
-        SelDataSet = datastructures(_, DeadDataSet),
-        set.member(DeadData, DeadDataSet),
-        datastruct_subsumed_by_list(ModuleInfo, ProcInfo, DeadData,
-            LiveDatastructs)
-    ;
-        true
-    ).
-
 apply_widening(ModuleInfo, ProcInfo, WideningLimit, WideningDone, !Sharing):-
     (
         !.Sharing = sharing_as_bottom,
Index: tests/hard_coded/Mercury.options
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/Mercury.options,v
retrieving revision 1.31
diff -u -r1.31 Mercury.options
--- tests/hard_coded/Mercury.options	21 Apr 2008 05:15:31 -0000	1.31
+++ tests/hard_coded/Mercury.options	23 Apr 2008 03:20:04 -0000
@@ -2,6 +2,7 @@
 MCFLAGS-any_call_hoist_bug = --loop-invariants
 MCFLAGS-bad_indirect_reuse =	--ctgc --no-common-struct
 MCFLAGS-bad_indirect_reuse2 =	--ctgc --no-common-struct
+MCFLAGS-bad_indirect_reuse2b =	--ctgc --no-common-struct
 MCFLAGS-bad_indirect_reuse3 =	--ctgc --no-common-struct
 MCFLAGS-checked_nondet_tailcall	= --checked-nondet-tailcalls
 MCFLAGS-checked_nondet_tailcall_noinline = --checked-nondet-tailcalls --no-inlining
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.347
diff -u -r1.347 Mmakefile
--- tests/hard_coded/Mmakefile	22 Apr 2008 04:41:25 -0000	1.347
+++ tests/hard_coded/Mmakefile	23 Apr 2008 03:20:04 -0000
@@ -354,6 +354,7 @@
 	CTGC_PROGS= \
 		bad_indirect_reuse \
 		bad_indirect_reuse2 \
+		bad_indirect_reuse2b \
 		bad_indirect_reuse3
 else
 	CTGC_PROGS=
Index: tests/hard_coded/bad_indirect_reuse2b.exp
===================================================================
RCS file: tests/hard_coded/bad_indirect_reuse2b.exp
diff -N tests/hard_coded/bad_indirect_reuse2b.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/bad_indirect_reuse2b.exp	23 Apr 2008 03:20:04 -0000
@@ -0,0 +1,2 @@
+hide(foo(1, 2))
+foo(2, 1)
Index: tests/hard_coded/bad_indirect_reuse2b.m
===================================================================
RCS file: tests/hard_coded/bad_indirect_reuse2b.m
diff -N tests/hard_coded/bad_indirect_reuse2b.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/bad_indirect_reuse2b.m	23 Apr 2008 03:20:04 -0000
@@ -0,0 +1,39 @@
+% Regression test.
+% Test the same thing as bad_indirect_reuse2 but with simpler code. 
+
+:- module bad_indirect_reuse2b.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module list.
+
+main(!IO) :-
+    copy(foo(1, 2), U),
+    H = hide(U),
+    oof(U, X),
+    io.write(H, !IO),
+    io.nl(!IO),
+    io.write(X, !IO),
+    io.nl(!IO).
+
+:- type foo
+    --->    foo(int, int).
+
+:- type hide
+    --->    hide(foo).
+
+:- pred oof(foo::in, foo::out) is det.
+:- pragma no_inline(oof/2).
+
+oof(foo(A, B), foo(B, A)).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sw=4 et wm=0 tw=0


--------------------------------------------------------------------------
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