[m-dev.] for review: default modes for higher-order func insts

David Overton dmo at cs.mu.OZ.AU
Fri Aug 3 11:37:12 AEST 2001


Hi,

This diff implements Ralph's suggestion which was discussed on
mercury-developers last week.

I still think it requires further consideration before committing
since it changes the language in a non-backwards-compatible way.
For those of us in Melbourne, perhaps we can disuss this in the
meeting this afternoon.


David

----

Estimated hours taken: 3
Branches: main

Implement a change to the mode system suggested by Ralph Becket to make use of
higher order functions a bit easier.

During mode checking of higher order calls, if the variable being called has a
higher-order function type, but only a ground inst with no higher-order
information, assume that it has the default function modes.

Also, when doing anything that might cause a variable's inst to lose higher
order mode information, report a mode error if the variable has a non-standard
higher order function mode.  Situations where this may occur are at call sites,
exit sites and when merging insts at the end of a branched goal.

Note that because of this restriction, this change is not backwards compatible.

compiler/inst_util.m:
	Define some predicates to check for and produce pred_inst_infos for
	default function modes.
	In 'inst_merge', ensure that higher order inst information is not lost
	from non-standard function insts.

compiler/inst_match.m:
	In 'inst_matches_initial' and 'inst_matches_final', ensure that higher
	order inst information is not lost from non-standard function insts.
	Also allow 'inst_matches_{initial,final,binding}' to succeed
	where the first inst is a standard function inst and the
	second is ground.

compiler/modecheck_call.m:
	In 'modecheck_higher_order_call', if the variable to be called has no
	pred_inst_info, but the correct higher-order function type, assume it
	has the default function modes. 

tests/hard_coded/Mmakefile:
tests/hard_coded/ho_func_default_inst.m:
tests/hard_coded/ho_func_default_inst.exp:
tests/invalid/Mmakefile:
tests/invalid/ho_default_func_1.m:
tests/invalid/ho_default_func_1.err_exp:
tests/invalid/ho_default_func_2.m:
tests/invalid/ho_default_func_2.err_exp:
	Add some test cases.

Index: compiler/inst_match.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/inst_match.m,v
retrieving revision 1.46
diff -u -r1.46 inst_match.m
--- compiler/inst_match.m	13 Oct 2000 13:55:28 -0000	1.46
+++ compiler/inst_match.m	3 Aug 2001 00:10:24 -0000
@@ -369,7 +369,10 @@
 	Uniq = mostly_unique,
 	bound_inst_list_is_ground(List, Info^module_info),
 	bound_inst_list_is_mostly_unique(List, Info^module_info).
-inst_matches_initial_3(ground(UniqA, _PredInst), any(UniqB), _, I, I) :-
+inst_matches_initial_3(ground(UniqA, GroundInstInfoA), any(UniqB), _,
+		Info, Info) :-
+	\+ ground_inst_info_is_nonstandard_func_mode(GroundInstInfoA,
+		Info^module_info),
 	unique_matches_initial(UniqA, UniqB).
 inst_matches_initial_3(ground(_Uniq, _PredInst), free, _, I, I).
 inst_matches_initial_3(ground(UniqA, GII_A), bound(UniqB, ListB), MaybeType,
@@ -532,7 +535,15 @@
 		uniqueness, maybe(type), inst_match_info, inst_match_info).
 :- mode ground_inst_info_matches_initial(in, in, in, in, in, out) is semidet.
 
-ground_inst_info_matches_initial(_, none, _, _) --> [].
+ground_inst_info_matches_initial(GroundInstInfoA, none, _, _) -->
+	ModuleInfo =^ module_info,
+	{ \+ ground_inst_info_is_nonstandard_func_mode(GroundInstInfoA,
+		ModuleInfo) }.
+ground_inst_info_matches_initial(none, higher_order(PredInstB), _, Type) -->
+	{ PredInstB = pred_inst_info(function, ArgModes, _Det) },
+	{ Arity = list__length(ArgModes) },
+	{ PredInstA = pred_inst_info_standard_func_mode(Arity) },
+	pred_inst_matches_initial(PredInstA, PredInstB, Type).
 ground_inst_info_matches_initial(higher_order(PredInstA),
 		higher_order(PredInstB), _, Type) -->
 	pred_inst_matches_initial(PredInstA, PredInstB, Type).
@@ -833,10 +844,15 @@
 	unique_matches_final(UniqA, UniqB),
 	bound_inst_list_is_ground(ListA, Info^module_info),
 	bound_inst_list_matches_uniq(ListA, UniqB, Info^module_info).
-inst_matches_final_3(ground(UniqA, _), any(UniqB), _, I, I) :-
-	unique_matches_final(UniqA, UniqB).
-inst_matches_final_3(ground(UniqA, _), bound(UniqB, ListB), MaybeType,
+inst_matches_final_3(ground(UniqA, GroundInstInfoA), any(UniqB), _,
 		Info, Info) :-
+	\+ ground_inst_info_is_nonstandard_func_mode(GroundInstInfoA,
+		Info^module_info),
+	unique_matches_final(UniqA, UniqB).
+inst_matches_final_3(ground(UniqA, GroundInstInfoA), bound(UniqB, ListB),
+		MaybeType, Info, Info) :-
+	\+ ground_inst_info_is_nonstandard_func_mode(GroundInstInfoA,
+		Info^module_info),
 	unique_matches_final(UniqA, UniqB),
 	bound_inst_list_is_ground(ListB, Info^module_info),
 	uniq_matches_bound_inst_list(UniqA, ListB, Info^module_info),
@@ -869,7 +885,15 @@
 		maybe(type), inst_match_info, inst_match_info).
 :- mode ground_inst_info_matches_final(in, in, in, in, out) is semidet.
 
-ground_inst_info_matches_final(_, none, _) --> [].
+ground_inst_info_matches_final(GroundInstInfoA, none, _) -->
+	ModuleInfo =^ module_info,
+	{ \+ ground_inst_info_is_nonstandard_func_mode(GroundInstInfoA,
+		ModuleInfo) }.
+ground_inst_info_matches_final(none, higher_order(PredInstB), Type) -->
+	{ PredInstB = pred_inst_info(function, ArgModes, _Det) },
+	{ Arity = list__length(ArgModes) },
+	{ PredInstA = pred_inst_info_standard_func_mode(Arity) },
+	pred_inst_matches_2(PredInstA, PredInstB, Type).
 ground_inst_info_matches_final(higher_order(PredInstA),
 		higher_order(PredInstB), MaybeType) -->
 	pred_inst_matches_2(PredInstA, PredInstB, MaybeType).
@@ -984,6 +1008,12 @@
 :- mode ground_inst_info_matches_binding(in, in, in, in) is semidet.
 
 ground_inst_info_matches_binding(_, none, _, _).
+ground_inst_info_matches_binding(none, higher_order(PredInstB), MaybeType,
+		ModuleInfo) :-
+	PredInstB = pred_inst_info(function, ArgModes, _Det),
+	Arity = list__length(ArgModes),
+	PredInstA = pred_inst_info_standard_func_mode(Arity),
+	pred_inst_matches_1(PredInstA, PredInstB, MaybeType, ModuleInfo).
 ground_inst_info_matches_binding(higher_order(PredInstA),
 		higher_order(PredInstB), MaybeType, ModuleInfo) :-
 	pred_inst_matches_1(PredInstA, PredInstB, MaybeType, ModuleInfo).
Index: compiler/inst_util.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/inst_util.m,v
retrieving revision 1.16
diff -u -r1.16 inst_util.m
--- compiler/inst_util.m	30 Mar 2001 06:04:22 -0000	1.16
+++ compiler/inst_util.m	2 Aug 2001 15:05:03 -0000
@@ -98,6 +98,25 @@
 	%       the same in both.
 
 %-----------------------------------------------------------------------------%
+
+	% Succeed iff the first argument is a function pred_inst_info
+	% with non-standard mode.
+
+:- pred pred_inst_info_is_nonstandard_func_mode(pred_inst_info, module_info).
+:- mode pred_inst_info_is_nonstandard_func_mode(in, in) is semidet.
+
+	% Succeed iff the first argument is a function ground_inst_info
+	% with non-standard mode.
+
+:- pred ground_inst_info_is_nonstandard_func_mode(ground_inst_info,
+			module_info).
+:- mode ground_inst_info_is_nonstandard_func_mode(in, in) is semidet.
+
+
+	% Return the standard mode for a function of the given arity.
+
+:- func pred_inst_info_standard_func_mode(arity) = pred_inst_info.
+
 %-----------------------------------------------------------------------------%
 
 :- implementation.
@@ -1413,6 +1432,13 @@
 		; pred_inst_matches(PredB, PredA, ModuleInfo) ->
 			GroundInstInfo = higher_order(PredA)
 		;
+			% If either is a function inst with non-standard
+			% modes, don't allow the higher-order
+			% information to be lost.
+			\+ pred_inst_info_is_nonstandard_func_mode(PredA,
+				ModuleInfo),
+			\+ pred_inst_info_is_nonstandard_func_mode(PredB,
+				ModuleInfo),
 			GroundInstInfo = none
 		)
 	;       
@@ -1421,6 +1447,10 @@
 	->
 		GroundInstInfo = constrained_inst_var(V)
 	;
+		\+ ground_inst_info_is_nonstandard_func_mode(GroundInstInfoA,
+			ModuleInfo),
+		\+ ground_inst_info_is_nonstandard_func_mode(GroundInstInfoB,
+			ModuleInfo),
 		GroundInstInfo = none
 	),
 	merge_uniq(UniqA, UniqB, Uniq).
@@ -1566,4 +1596,22 @@
 	).
 
 %-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+pred_inst_info_is_nonstandard_func_mode(PredInstInfo, ModuleInfo) :-
+	PredInstInfo = pred_inst_info(function, ArgModes, _),
+	Arity = list__length(ArgModes),
+	\+ pred_inst_matches(pred_inst_info_standard_func_mode(Arity),
+		PredInstInfo, ModuleInfo).
+
+ground_inst_info_is_nonstandard_func_mode(GroundInstInfo, ModuleInfo) :-
+	GroundInstInfo = higher_order(PredInstInfo),
+	pred_inst_info_is_nonstandard_func_mode(PredInstInfo, ModuleInfo).
+
+pred_inst_info_standard_func_mode(Arity) =
+		pred_inst_info(function, ArgModes, det) :-
+	in_mode(InMode),
+	out_mode(OutMode),
+	ArgModes = list__duplicate(Arity - 1, InMode) ++ [OutMode].
+
 %-----------------------------------------------------------------------------%
Index: compiler/modecheck_call.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modecheck_call.m,v
retrieving revision 1.38
diff -u -r1.38 modecheck_call.m
--- compiler/modecheck_call.m	17 Jan 2001 01:42:04 -0000	1.38
+++ compiler/modecheck_call.m	2 Aug 2001 15:25:10 -0000
@@ -69,7 +69,7 @@
 %-----------------------------------------------------------------------------%
 
 :- implementation.
-:- import_module hlds_data, instmap, prog_data, (inst).
+:- import_module hlds_data, instmap, prog_data, (inst), inst_util, type_util.
 :- import_module mode_info, mode_debug, modes, mode_util, mode_errors.
 :- import_module clause_to_proc, inst_match.
 :- import_module det_report, unify_proc.
@@ -87,7 +87,20 @@
 	inst_expand(ModuleInfo0, PredVarInst0, PredVarInst),
 	list__length(Args0, Arity),
 	(
-		PredVarInst = ground(_Uniq, higher_order(PredInstInfo)),
+		PredVarInst = ground(_Uniq, GroundInstInfo),
+		(
+			GroundInstInfo = higher_order(PredInstInfo)
+		;
+			% If PredVar has no higher-order inst
+			% information, but is a function type, then
+			% assume the default function mode.
+			GroundInstInfo = none,
+			mode_info_get_var_types(ModeInfo0, VarTypes),
+			map__lookup(VarTypes, PredVar, Type),
+			type_is_higher_order(Type, function, _, ArgTypes),
+			PredInstInfo = pred_inst_info_standard_func_mode(
+					list__length(ArgTypes))
+		),
 		PredInstInfo = pred_inst_info(PredOrFunc, Modes0, Det0),
 		list__length(Modes0, Arity)
 	->
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.124
diff -u -r1.124 Mmakefile
--- tests/hard_coded/Mmakefile	1 Aug 2001 00:31:39 -0000	1.124
+++ tests/hard_coded/Mmakefile	3 Aug 2001 00:18:09 -0000
@@ -62,6 +62,7 @@
 	higher_order_syntax \
 	higher_order_syntax2 \
 	higher_order_type_manip \
+	ho_func_default_inst \
 	ho_func_reg \
 	ho_order \
 	ho_order2 \
Index: tests/hard_coded/ho_func_default_inst.exp
===================================================================
RCS file: tests/hard_coded/ho_func_default_inst.exp
diff -N tests/hard_coded/ho_func_default_inst.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/ho_func_default_inst.exp	3 Aug 2001 00:18:47 -0000
@@ -0,0 +1,2 @@
+hello
+world
Index: tests/hard_coded/ho_func_default_inst.m
===================================================================
RCS file: tests/hard_coded/ho_func_default_inst.m
diff -N tests/hard_coded/ho_func_default_inst.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/ho_func_default_inst.m	3 Aug 2001 00:17:04 -0000
@@ -0,0 +1,43 @@
+% This test checks that a higher order func type with inst ground is 
+% able to be treated as a though it has the default function mode.
+
+:- module ho_func_default_inst.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module map.
+
+main -->
+	{ Map = map },
+	{ F1 = Map ^ det_elem(1) },
+	{ F2 = Map ^ det_elem(2) },
+	io__write_string(F1(1)),
+	io__nl,
+	write_func(F2).
+
+:- type t == (func(int) = string).
+
+:- func map = map(int, t).
+
+map = (map__init ^ elem(1) := hello) ^ elem(2) := world.
+
+:- pred write_func(t, io, io) is det.
+:- mode write_func(func(in) = out is det, di, uo) is det.
+
+write_func(F) -->
+	io__write_string(F(1)),
+	io__nl.
+
+:- func hello(int) = string.
+
+hello(_) = "hello".
+	
+:- func world(int) = string.
+
+world(_) = "world".
Index: tests/invalid/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/invalid/Mmakefile,v
retrieving revision 1.92
diff -u -r1.92 Mmakefile
--- tests/invalid/Mmakefile	10 Jul 2001 10:45:35 -0000	1.92
+++ tests/invalid/Mmakefile	3 Aug 2001 01:09:58 -0000
@@ -18,6 +18,7 @@
 	aditi_update_errors.m \
 	aditi_update_mode_errors.m \
 	duplicate_instance_2.m \
+	ho_default_func_2.m \
 	imported_mode.m \
 	partial_implied_mode.m \
 	test_nested.m \
@@ -45,6 +46,7 @@
 	field_syntax_error.m \
 	func_errors.m \
 	funcs_as_preds.m \
+	ho_default_func_1.m \
 	ho_type_mode_bug.m \
 	ho_unique_error.m \
 	impure_method_impl.m \
Index: tests/invalid/ho_default_func_1.err_exp
===================================================================
RCS file: tests/invalid/ho_default_func_1.err_exp
diff -N tests/invalid/ho_default_func_1.err_exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/ho_default_func_1.err_exp	3 Aug 2001 01:04:38 -0000
@@ -0,0 +1,6 @@
+ho_default_func_1.m:029: In clause for `baz(in, out)':
+ho_default_func_1.m:029:   in call to function `std_util:univ/1':
+ho_default_func_1.m:029:   mode error: arguments `TypeInfo_13, V_7, V_6'
+ho_default_func_1.m:029:   have insts `unique(private_builtin:type_info(unique(<type_ctor_info for :func/0>), unique(2), unique(<type_ctor_info for :int/0>), unique(<type_ctor_info for :int/0>))), /* unique */(func((free -> ground)) = (ground -> ground) is det), free',
+ho_default_func_1.m:029:   which does not match any of the modes for function `std_util:univ/1'.
+For more information, try recompiling with `-E'.
Index: tests/invalid/ho_default_func_1.m
===================================================================
RCS file: tests/invalid/ho_default_func_1.m
diff -N tests/invalid/ho_default_func_1.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/ho_default_func_1.m	3 Aug 2001 01:00:42 -0000
@@ -0,0 +1,34 @@
+% Compiling this module should generate an error message since
+% it tries to cast a non-standard func inst to ground.
+
+:- module ho_default_func_1.
+
+:- interface.
+:- import_module io.
+
+:- pred main(io__state, io__state).
+:- mode main(di, uo) is det.
+
+:- implementation.
+
+:- import_module int, std_util.
+
+main -->
+	{ baz(foo, F) },
+	io__write_int(F(42)), nl.
+
+:- func foo(int) = int.
+foo(X) = X + 1.
+
+:- func bar(int) = int.
+:- mode bar(out) = in is det.
+bar(X) = X + 1.
+
+:- pred baz(T::in, T::out) is det.
+baz(X, Y) :-
+	( univ_to_type(univ(bar), Y0) ->
+		Y = Y0
+	;
+		Y = X
+	).
+
Index: tests/invalid/ho_default_func_2.err_exp
===================================================================
RCS file: tests/invalid/ho_default_func_2.err_exp
diff -N tests/invalid/ho_default_func_2.err_exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/ho_default_func_2.err_exp	3 Aug 2001 01:05:44 -0000
@@ -0,0 +1,5 @@
+ho_default_func_2.m:038: In clause for `baz(out)':
+ho_default_func_2.m:038:   in argument 1 of call to function `ho_default_func_2:id:mkid/1':
+ho_default_func_2.m:038:   mode error: variable `V_2' has instantiatedness `/* unique */(func((free -> ground)) = (ground -> ground) is det)',
+ho_default_func_2.m:038:   expected instantiatedness was `ground'.
+For more information, try recompiling with `-E'.
Index: tests/invalid/ho_default_func_2.m
===================================================================
RCS file: tests/invalid/ho_default_func_2.m
diff -N tests/invalid/ho_default_func_2.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/ho_default_func_2.m	3 Aug 2001 01:04:58 -0000
@@ -0,0 +1,53 @@
+% Compiling this module should generate an error message since
+% it tries to cast a non-standard func inst to ground.
+
+:- module ho_default_func_2.
+
+:- interface.
+:- import_module io.
+
+:- pred main(io__state, io__state).
+:- mode main(di, uo) is det.
+
+:- implementation.
+
+:- import_module ho_default_func_2__sub.
+:- import_module ho_default_func_2__id.
+
+:- import_module int, std_util.
+
+main -->
+	{ baz(IdF), eq(getval(IdF), F) },
+	do_io(F).
+
+:- func foo(int) = int.
+foo(X) = X + 1.
+
+:- func bar(int) = int.
+:- mode bar(out) = in is det.
+bar(X) = X + 1.
+
+:- module sub.
+:- interface.
+:- type t.
+:- pred baz(id(t)::out) is det.
+:- pred eq(t::in, t::out) is det.
+:- pred do_io(t::in, io__state::di, io__state::uo) is det.
+:- implementation.
+:- type t == (func(int) = int).
+baz(mkid(bar)).
+eq(X,X).
+do_io(F) --> io__write_int(F(42)), nl.
+:- end_module sub.
+
+:- module id.
+:- interface.
+:- type id(T).
+:- func mkid(T) = id(T).
+:- func getval(id(T)) = T.
+:- implementation.
+:- type id(T) ---> id(T).
+mkid(X) = id(X).
+getval(id(X)) = X.
+:- end_module id.
+
-- 
David Overton      Department of Computer Science & Software Engineering
PhD Student        The University of Melbourne, Victoria 3010, Australia
+61 3 8344 9159    http://www.cs.mu.oz.au/~dmo
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list