[m-rev.] for review: fix typeclass bug

Simon Taylor stayl at cs.mu.OZ.AU
Fri Jul 26 18:30:11 AEST 2002


Estimated hours taken: 5
Branches: main

compiler/typecheck.m:
	Fix a bug in the handling of superclass constraints where
	some of the argument variables of the subclass don't appear
	in the superclass constraint, such as in class `bar' below.
	:- typeclass foo(T, U) <= bar(T, U).
	:- typeclass bar(T, U) <= baz(T).

	When calling a method of baz with a universal constraint in
	the predicate declaration of foo(A, B), the variable B
	was not being substituted correctly in the constraint
	proofs, resulting in an abort in polymorphism.

	Simplify the code by separating out some complicated
	lambdas into separate predicates.

tests/hard_coded/typeclasses/Mmakefile:
tests/hard_coded/typeclasses/superclass_bug3.{m,exp}:
	Test case.

Index: compiler/typecheck.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/typecheck.m,v
retrieving revision 1.323
diff -u -u -r1.323 typecheck.m
--- compiler/typecheck.m	26 Jul 2002 06:33:12 -0000	1.323
+++ compiler/typecheck.m	26 Jul 2002 06:48:16 -0000
@@ -4487,7 +4487,7 @@
 		Constraints, Changed) :-
 	(
 		Parents = [],
-		eliminate_constraint_by_class_rules(C, HeadTypeParams, 
+		eliminate_constraint_by_class_rules(C, _, _, HeadTypeParams, 
 			AssumedConstraints,
 			SuperClassTable, TVarSet, Parents, Proofs0, Proofs1)
 	->
@@ -4512,15 +4512,16 @@
 	% original constraint that we are trying to prove. (These are the
 	% type variables that must not be bound as we search through the
 	% superclass relation).
-:- pred eliminate_constraint_by_class_rules(class_constraint, list(tvar),
+:- pred eliminate_constraint_by_class_rules(class_constraint, class_constraint,
+	tsubst, list(tvar),
 	list(class_constraint), superclass_table, tvarset,
 	list(class_constraint),
 	map(class_constraint, constraint_proof),
 	map(class_constraint, constraint_proof)).
-:- mode eliminate_constraint_by_class_rules(in, in, in, in, in, in, in, out) 
-	is semidet.
+:- mode eliminate_constraint_by_class_rules(in, out, out,
+	in, in, in, in, in, in, out) is semidet.
 
-eliminate_constraint_by_class_rules(C, ConstVars,
+eliminate_constraint_by_class_rules(C, SubstC, SubClassSubst, ConstVars,
 		AssumedConstraints, SuperClassTable,
 		TVarSet, ParentConstraints, Proofs0, Proofs) :-
 
@@ -4536,60 +4537,21 @@
 		% Convert all the subclass_details into class_constraints by
 		% doing the appropriate variable renaming and applying the
 		% type variable bindings.
-	SubDetailsToConstraint = (pred(SubClassDetails::in, SubC::out) 
-			is det :-
-		SubClassDetails = subclass_details(SuperVars0, SubID,
-			SubVars0, SuperVarset),
-
-			% Rename the variables from the typeclass
-			% declaration into those of the current pred
-		varset__merge_subst(TVarSet, SuperVarset, _NewTVarSet, 
-			RenameSubst),
-		term__var_list_to_term_list(SubVars0, SubVars1),
-		term__apply_substitution_to_list(SubVars1, 
-			RenameSubst, SubVars),
-		term__apply_substitution_to_list(SuperVars0,
-			RenameSubst, SuperVars),
-
-			% Work out what the (renamed) vars from the
-			% typeclass declaration are bound to here
-		map__init(Empty),
-		(
-			type_unify_list(SuperVars, SuperClassTypes, [],
-				Empty, Bindings)
-		->
-			SubID = class_id(SubName, _SubArity),
-			term__apply_substitution_to_list(SubVars, Bindings,
-				SubClassTypes),
-			SubC = constraint(SubName, SubClassTypes)
-		;
-			error("eliminate_constraint_by_class_rules: type_unify_list failed")
-		)
-	),
-	list__map(SubDetailsToConstraint, SubClasses, SubClassConstraints),
+	list__map(subclass_details_to_constraint(TVarSet, SuperClassTypes),
+		SubClasses, SubClassConstraints),
 
 	(
 			% Do the first level of search. We search for
 			% an assumed constraint which unifies with any
 			% of the subclass constraints.
-		FindSub = (pred(TheConstraint::in) is semidet :-
-			some [SubClassConstraint] (
-				TheConstraint = constraint(TheConstraintClass,
-					TheConstraintTypes),
-				list__member(SubClassConstraint, 
-					SubClassConstraints),
-				SubClassConstraint = 
-					constraint(TheConstraintClass, 
-					SubClassConstraintTypes),
-				map__init(EmptySub),
-				type_unify_list(SubClassConstraintTypes, 
-					TheConstraintTypes,
-					ConstVars, EmptySub, _)
-			)
-		),
-		find_first_match(FindSub, AssumedConstraints, Sub)
+		find_first(
+			match_assumed_constraint(ConstVars,
+				SubClassConstraints),
+			AssumedConstraints, SubClass - SubClassSubst0)
 	->
-		map__set(Proofs0, C, superclass(Sub), Proofs)
+		SubClassSubst = SubClassSubst0,
+		apply_rec_subst_to_constraint(SubClassSubst, C, SubstC),
+		map__set(Proofs0, SubstC, superclass(SubClass), Proofs)
 	;
 		NewParentConstraints = [C|ParentConstraints],
 
@@ -4598,18 +4560,43 @@
 		SubClassSearch = (pred(Constraint::in, CnstrtAndProof::out) 
 				is semidet :-
 			eliminate_constraint_by_class_rules(Constraint, 
+				SubstConstraint, SubClassSubst0,
 				ConstVars, AssumedConstraints, SuperClassTable,
 				TVarSet, NewParentConstraints,
 				Proofs0, SubProofs),
-			CnstrtAndProof = Constraint - SubProofs
+			CnstrtAndProof = {SubstConstraint,
+				SubClassSubst0, SubProofs}
 		),
 			% XXX this could (and should) be more efficient. 
 			% (ie. by manually doing a "cut").
 		find_first(SubClassSearch, SubClassConstraints,
-			NewSub - NewProofs),
-		map__set(NewProofs, C, superclass(NewSub), Proofs)
+			{NewSubClass, SubClassSubst, NewProofs}),
+		apply_rec_subst_to_constraint(SubClassSubst, C, SubstC),
+		map__set(NewProofs, SubstC, superclass(NewSubClass), Proofs)
 	).
 
+:- pred match_assumed_constraint(list(tvar)::in, list(class_constraint)::in,
+	class_constraint::in, pair(class_constraint, tsubst)::out) is semidet.
+
+match_assumed_constraint(ConstVars, SubClassConstraints,
+		AssumedConstraint, Match) :-
+	find_first(match_assumed_constraint_2(ConstVars, AssumedConstraint), 
+		SubClassConstraints, Match).
+
+:- pred match_assumed_constraint_2(list(tvar)::in, class_constraint::in,
+	class_constraint::in, pair(class_constraint, tsubst)::out) is semidet.
+
+match_assumed_constraint_2(ConstVars, AssumedConstraint,
+		SubClassConstraint, Match) :-
+	AssumedConstraint = constraint(AssumedConstraintClass,
+		AssumedConstraintTypes),
+	SubClassConstraint = constraint(AssumedConstraintClass,
+		SubClassConstraintTypes),
+	map__init(EmptySub),
+	type_unify_list(SubClassConstraintTypes, AssumedConstraintTypes,
+		ConstVars, EmptySub, AssumedConstraintSub),
+	Match = AssumedConstraint - AssumedConstraintSub.
+
 	% XXX this should probably work its way into the library.
 	% This is just like list__filter_map except that it only returns
 	% the first match:
@@ -4638,6 +4625,39 @@
 		Result = X
 	;
 		find_first_match(Pred, Xs, Result)
+	).
+
+:- pred subclass_details_to_constraint(tvarset::in, list(type)::in,
+		subclass_details::in, class_constraint::out) is det.
+
+subclass_details_to_constraint(TVarSet, SuperClassTypes,
+			SubClassDetails, SubC) :-
+	SubClassDetails = subclass_details(SuperVars0, SubID,
+		SubVars0, SuperVarset),
+
+		% Rename the variables from the typeclass
+		% declaration into those of the current pred
+	varset__merge_subst(TVarSet, SuperVarset, _NewTVarSet, 
+		RenameSubst),
+	term__var_list_to_term_list(SubVars0, SubVars1),
+	term__apply_substitution_to_list(SubVars1, 
+		RenameSubst, SubVars),
+	term__apply_substitution_to_list(SuperVars0,
+		RenameSubst, SuperVars),
+
+		% Work out what the (renamed) vars from the
+		% typeclass declaration are bound to here
+	map__init(Empty),
+	(
+		type_unify_list(SuperVars, SuperClassTypes, [],
+			Empty, Bindings)
+	->
+		SubID = class_id(SubName, _SubArity),
+		term__apply_substitution_to_list(SubVars, Bindings,
+			SubClassTypes),
+		SubC = constraint(SubName, SubClassTypes)
+	;
+		error("eliminate_constraint_by_class_rules: type_unify_list failed")
 	).
 
 	%
Index: tests/hard_coded/typeclasses/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/typeclasses/Mmakefile,v
retrieving revision 1.45
diff -u -u -r1.45 Mmakefile
--- tests/hard_coded/typeclasses/Mmakefile	26 Jul 2002 06:33:18 -0000	1.45
+++ tests/hard_coded/typeclasses/Mmakefile	26 Jul 2002 06:36:29 -0000
@@ -49,6 +49,7 @@
 	reordered_existential_constraint \
 	superclass_bug \
 	superclass_bug2 \
+	superclass_bug3 \
 	superclass_call \
 	test_default_func_mode \
 	tuple_instance \
Index: tests/hard_coded/typeclasses/superclass_bug3.exp
===================================================================
RCS file: tests/hard_coded/typeclasses/superclass_bug3.exp
diff -N tests/hard_coded/typeclasses/superclass_bug3.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/typeclasses/superclass_bug3.exp	26 Jul 2002 05:00:14 -0000
@@ -0,0 +1 @@
+1
Index: tests/hard_coded/typeclasses/superclass_bug3.m
===================================================================
RCS file: tests/hard_coded/typeclasses/superclass_bug3.m
diff -N tests/hard_coded/typeclasses/superclass_bug3.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/typeclasses/superclass_bug3.m	26 Jul 2002 04:59:37 -0000
@@ -0,0 +1,42 @@
+:- module superclass_bug3.
+
+:- interface.
+
+:- import_module io.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+:- import_module string, std_util.
+
+main -->
+	{ parse_result_entry(unit, 1, unit, String) },
+	io__write_string(String),
+	io__nl.
+
+:- typeclass analysis(FuncInfo, Call, Answer)
+		<= call_pattern(FuncInfo, Call) where [].
+
+:- typeclass call_pattern(FuncInfo, Call) <= to_string(Call) where [].
+
+:- typeclass to_string(S) where [
+		func to_string(S) = string
+	].
+
+:- instance analysis(unit, int, unit) where [].
+:- instance call_pattern(unit, int) where [].
+:- instance to_string(int) where [
+		to_string(S) = string__int_to_string(S)
+].
+
+:- pred parse_result_entry(FuncInfo::in, Call::in,
+	Answer::in, string::out) is det <= analysis(FuncInfo, Call, Answer).
+
+:- implementation.
+
+:- import_module list.
+
+parse_result_entry(_FuncInfo, Call, _Answer, String) :-
+	String = to_string(Call).
+
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list