diff: detect circular superclasses

David Glen JEFFERY dgj at cs.mu.OZ.AU
Wed May 6 14:31:49 AEST 1998


Hi, 

Can you please review this, Fergus? It is a new version of my changes to
make_hlds.m, updated to check for cycles in the superclass relation.



Index: compiler/make_hlds.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/make_hlds.m,v
retrieving revision 1.263
diff -u -r1.263 make_hlds.m
--- make_hlds.m	1998/03/04 19:47:34	1.263
+++ make_hlds.m	1998/05/06 04:17:16
@@ -1289,10 +1289,11 @@
 module_add_class_defn(Module0, Constraints, Name, Vars, Interface, VarSet,
 		Context, Status, Module) -->
 	{ module_info_classes(Module0, Classes0) },
+	{ module_info_superclasses(Module0, SuperClasses0) },
 	{ list__length(Vars, ClassArity) },
-	{ Key = class_id(Name, ClassArity) },
+	{ ClassId = class_id(Name, ClassArity) },
 	(
-		{ map__search(Classes0, Key, OldValue) }
+		{ map__search(Classes0, ClassId, OldValue) }
 	->
 		{ OldValue = hlds_class_defn(_, _, _, _, OldContext) },
 		multiple_def_error(Name, ClassArity, "typeclass", 
@@ -1311,13 +1312,57 @@
 		{ list__filter_map(IsYes, PredProcIds0, PredProcIds) },
 		{ Value = hlds_class_defn(Constraints, Vars, PredProcIds, 
 			VarSet, Context) },
-		{ map__det_insert(Classes0, Key, Value, Classes) },
+		{ map__det_insert(Classes0, ClassId, Value, Classes) },
 		{ module_info_set_classes(Module1, Classes, Module2) },
+
+			% insert an entry into the super class table for each
+			% super class of this class
+		{ AddSuper = lambda([Super::in, Ss0::in, Ss::out] is det,
+			(
+				Super = constraint(SuperName, SuperTypes),
+				list__length(SuperTypes, SuperClassArity),
+				term__vars_list(SuperTypes, SuperVars),
+				SuperClassId = class_id(SuperName,
+					SuperClassArity),
+				SubClassDetails = subclass_details(SuperVars,
+					ClassId, Vars, VarSet),
+				multi_map__set(Ss0, SuperClassId,
+					SubClassDetails, Ss)
+			)) },
+		{ list__foldl(AddSuper, Constraints, 
+			SuperClasses0, SuperClasses) },
+
+			% Check that all type class names that are mentioned
+			% here are for type classes that have already been
+			% declared. This ensures that there are no cycles in
+			% the superclass relation
+		{ CheckCircular = lambda([C::in, IO0::di, IO::uo] is det,
+			(
+				C = constraint(ClassName, Types),
+				list__length(Types, Arity),
+				(
+					map__search(Classes0, 
+						class_id(ClassName, Arity), _)
+				->
+					IO = IO0
+				;
+					undefined_type_class_error(ClassName,
+						Arity, Context, 
+						"type class constraint",
+						IO0, IO1),
+					io__set_exit_status(1, IO1, IO)
+				)
+			)) },
+		list__foldl(CheckCircular, Constraints),
+			
+		{ module_info_set_superclasses(Module2, 
+			SuperClasses, Module3) },
+
 			% When we find the class declaration, make an
 			% entry for the instances.
-		{ module_info_instances(Module2, Instances0) },
-		{ map__det_insert(Instances0, Key, [], Instances) },
-		{ module_info_set_instances(Module2, Instances, Module) }
+		{ module_info_instances(Module3, Instances0) },
+		{ map__det_insert(Instances0, ClassId, [], Instances) },
+		{ module_info_set_instances(Module3, Instances, Module) }
 	).
 
 :- pred module_add_class_interface(module_info, sym_name, list(var),
@@ -4219,6 +4264,21 @@
 		io__write_string(DeclString),
 		io__write_string("' declaration.\n")
 	).
+
+:- pred undefined_type_class_error(sym_name, int, term__context, string,
+				io__state, io__state).
+:- mode undefined_type_class_error(in, in, in, in, di, uo) is det.
+
+undefined_type_class_error(ClassName, Arity, Context, Description) -->
+	io__set_exit_status(1),
+	prog_out__write_context(Context),
+	io__write_string("Error: "),
+	io__write_string(Description),
+	io__write_string(" for\n"),
+	prog_out__write_context(Context),
+	io__write_string("  `"),
+	hlds_out__write_pred_call_id(ClassName/Arity),
+	io__write_string("' without preceding typeclass declaration.\n").
 
 :- pred unspecified_det_for_local(sym_name, arity, pred_or_func, term__context, 
 				io__state, io__state).




New file: superclass_cycle.m, to go in tests/invalid
--------------------------------------------------------
:- module superclass_cycle.

:- interface.


:- typeclass c1(T) <= c2(T) where [
].

:- typeclass c2(T) <= c1(T) where [
].
--------------------------------------------------------


love and cuddles,
dgj
-- 
David Jeffery (dgj at cs.mu.oz.au) |  Marge: Did you just call everyone "chicken"?
MEngSc student,                 |  Homer: Noooo.  I swear on this Bible!
Department of Computer Science  |  Marge: That's not a Bible; that's a book of
University of Melbourne         |         carpet samples!
Australia                       |  Homer: Ooooh... Fuzzy.



More information about the developers mailing list