mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 06:47:17 +00:00
Allow typeclass instance declarations to contain more than one clause
Estimated hours taken: 5 Allow typeclass instance declarations to contain more than one clause for each method. Also improve some error messages. compiler/check_typeclass.m: Allow typeclass instance declarations to contain more than one clause for each method, by combining the different clauses for each method into a single definition. Rewrite the code to check for bogus method names in instance declarations. This rewrite was necessitated by the change mentioned above, but also improved the quality of the error message (it now prints the name of the bogus method) and fixed some bugs that sometimes resulted in spurious flow-on error messages. Fix some problems where we were not passing the correct arity for functions (e.g. to make_introduced_pred_name). tests/invalid/Mmakefile: tests/invalid/typeclass_bogus_method.m: tests/invalid/typeclass_bogus_method.err_exp: Add a new regression test. tests/invalid/tc_err*.err_exp: tests/invalid/typeclass_test_*.err_exp: Update the expected output for these test cases, to reflect the improved error messages. doc/reference_manual.texi: Update the documentation to reflect this change. NEWS: Mention that we now allow clauses in instance declarations.
This commit is contained in:
6
NEWS
6
NEWS
@@ -48,7 +48,11 @@ Changes to the Mercury language:
|
|||||||
|
|
||||||
The old syntax is still accepted but is deprecated. Support for it may
|
The old syntax is still accepted but is deprecated. Support for it may
|
||||||
eventually be dropped.
|
eventually be dropped.
|
||||||
|
|
||||||
|
* Type class methods can now be defined by listing the clauses
|
||||||
|
directly in the instance declaration. You no longer need to define a
|
||||||
|
separate predicate or function for each type class method definition.
|
||||||
|
|
||||||
Changes to the standard library:
|
Changes to the standard library:
|
||||||
|
|
||||||
* We've added a pretty printing module, `pprint', to the standard library.
|
* We've added a pretty printing module, `pprint', to the standard library.
|
||||||
|
|||||||
@@ -49,7 +49,8 @@
|
|||||||
|
|
||||||
:- interface.
|
:- interface.
|
||||||
|
|
||||||
:- import_module hlds_module, make_hlds, bool, io.
|
:- import_module hlds_module, make_hlds.
|
||||||
|
:- import_module bool, io.
|
||||||
|
|
||||||
:- pred check_typeclass__check_instance_decls(module_info, qual_info,
|
:- pred check_typeclass__check_instance_decls(module_info, qual_info,
|
||||||
module_info, bool, io__state, io__state).
|
module_info, bool, io__state, io__state).
|
||||||
@@ -57,11 +58,16 @@
|
|||||||
|
|
||||||
:- implementation.
|
:- implementation.
|
||||||
|
|
||||||
:- import_module map, list, std_util, hlds_pred, hlds_data, prog_data, require.
|
:- import_module prog_data, prog_out.
|
||||||
:- import_module type_util, assoc_list, mode_util, inst_match, hlds_module.
|
:- import_module hlds_pred, hlds_data, hlds_goal, hlds_out.
|
||||||
:- import_module typecheck, int, globals, options, make_hlds, error_util.
|
:- import_module type_util, typecheck, mode_util, inst_match.
|
||||||
:- import_module base_typeclass_info, string, hlds_goal, set, prog_out.
|
:- import_module base_typeclass_info.
|
||||||
:- import_module mercury_to_mercury, varset, term.
|
:- import_module mercury_to_mercury, error_util.
|
||||||
|
:- import_module globals, options.
|
||||||
|
|
||||||
|
:- import_module int, string.
|
||||||
|
:- import_module list, assoc_list, map, set, term, varset.
|
||||||
|
:- import_module std_util, require.
|
||||||
|
|
||||||
:- type error_message == pair(prog_context, list(format_component)).
|
:- type error_message == pair(prog_context, list(format_component)).
|
||||||
:- type error_messages == list(error_message).
|
:- type error_messages == list(error_message).
|
||||||
@@ -190,66 +196,31 @@ check_class_instance(ClassId, SuperClasses, Vars, ClassInterface, ClassVarSet,
|
|||||||
MaybePredProcs1, G, H),
|
MaybePredProcs1, G, H),
|
||||||
(
|
(
|
||||||
MaybePredProcs1 = yes(_),
|
MaybePredProcs1 = yes(_),
|
||||||
MaybePredProcs2 = MaybePredProcs1
|
MaybePredProcs = MaybePredProcs1
|
||||||
;
|
;
|
||||||
MaybePredProcs1 = no,
|
MaybePredProcs1 = no,
|
||||||
MaybePredProcs2 = yes([])
|
MaybePredProcs = yes([])
|
||||||
),
|
),
|
||||||
|
|
||||||
%
|
%
|
||||||
% Make sure the list of instance methods is in the same
|
% Make sure the list of instance methods is in the same
|
||||||
% order as the methods in the class definition. intermod.m
|
% order as the methods in the class definition. intermod.m
|
||||||
% relies on this. If there were errors, don't change the
|
% relies on this
|
||||||
% list of methods.
|
OrderedInstanceMethods = list__reverse(RevInstanceMethods),
|
||||||
%
|
|
||||||
(
|
|
||||||
list__length(RevInstanceMethods,
|
|
||||||
list__length(InstanceMethods))
|
|
||||||
->
|
|
||||||
OrderedInstanceMethods =
|
|
||||||
list__reverse(RevInstanceMethods)
|
|
||||||
;
|
|
||||||
OrderedInstanceMethods = InstanceMethods
|
|
||||||
),
|
|
||||||
|
|
||||||
InstanceDefn2 = hlds_instance_defn(A, B, C, D,
|
InstanceDefn2 = hlds_instance_defn(A, B, C, D,
|
||||||
concrete(OrderedInstanceMethods),
|
concrete(OrderedInstanceMethods),
|
||||||
MaybePredProcs2, G, H),
|
MaybePredProcs, G, H),
|
||||||
|
|
||||||
%
|
%
|
||||||
% Check if there are any instance methods left over,
|
% Check if there are any instance methods left over,
|
||||||
% for which we did not produce a pred_id/proc_id;
|
% which did not match any of the methods from the
|
||||||
% if there are any, the instance declaration must have
|
% class interface.
|
||||||
% specified some methods that don't occur in the class.
|
|
||||||
%
|
%
|
||||||
InstanceDefn2 = hlds_instance_defn(_, Context, _, _,
|
InstanceDefn2 = hlds_instance_defn(_, Context,
|
||||||
_, MaybePredProcs, _, _),
|
_, _, _, _, _, _),
|
||||||
(
|
check_for_bogus_methods(InstanceMethods, ClassId, PredIds,
|
||||||
MaybePredProcs = yes(PredProcs),
|
Context, ModuleInfo1, Errors1, Errors2)
|
||||||
|
|
||||||
% Check that we wind with a procedure for each
|
|
||||||
% proc in the type class interface.
|
|
||||||
list__same_length(PredProcs, ClassInterface),
|
|
||||||
|
|
||||||
% Check that we wind with a pred for each
|
|
||||||
% pred in the instance class interface.
|
|
||||||
list__map((pred(PP::in, P::out) is det :-
|
|
||||||
PP = hlds_class_proc(P, _)), PredProcs, Preds0),
|
|
||||||
list__remove_dups(Preds0, Preds),
|
|
||||||
list__same_length(Preds, InstanceMethods)
|
|
||||||
->
|
|
||||||
Errors2 = Errors1
|
|
||||||
;
|
|
||||||
ClassId = class_id(ClassName, ClassArity),
|
|
||||||
prog_out__sym_name_to_string(ClassName,
|
|
||||||
ClassNameString),
|
|
||||||
string__int_to_string(ClassArity, ClassArityString),
|
|
||||||
string__append_list([
|
|
||||||
"In instance declaration for `",
|
|
||||||
ClassNameString, "/", ClassArityString, "': ",
|
|
||||||
"incorrect method name(s)."],
|
|
||||||
NewError),
|
|
||||||
Errors2 = [Context - [words(NewError)] | Errors1]
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
|
|
||||||
% check that the superclass constraints are satisfied for the
|
% check that the superclass constraints are satisfied for the
|
||||||
@@ -258,6 +229,74 @@ check_class_instance(ClassId, SuperClasses, Vars, ClassInterface, ClassVarSet,
|
|||||||
InstanceDefn2, InstanceDefn,
|
InstanceDefn2, InstanceDefn,
|
||||||
Errors2 - ModuleInfo1, Errors - ModuleInfo).
|
Errors2 - ModuleInfo1, Errors - ModuleInfo).
|
||||||
|
|
||||||
|
%
|
||||||
|
% Check if there are any instance methods left over,
|
||||||
|
% which did not match any of the methods from the
|
||||||
|
% class interface. If so, add an appropriate error
|
||||||
|
% message to the list of error messages.
|
||||||
|
%
|
||||||
|
:- pred check_for_bogus_methods(list(instance_method), class_id, list(pred_id),
|
||||||
|
prog_context, module_info, error_messages, error_messages).
|
||||||
|
:- mode check_for_bogus_methods(in, in, in, in, in, in, out) is det.
|
||||||
|
|
||||||
|
check_for_bogus_methods(InstanceMethods, ClassId, ClassPredIds, Context,
|
||||||
|
ModuleInfo1, Errors0, Errors) :-
|
||||||
|
module_info_get_predicate_table(ModuleInfo1, PredTable),
|
||||||
|
DefnIsOK = (pred(Method::in) is semidet :-
|
||||||
|
% Find this method definition's p/f, name, arity
|
||||||
|
Method = instance_method(MethodPredOrFunc,
|
||||||
|
MethodName, _MethodDefn,
|
||||||
|
MethodArity, _Context),
|
||||||
|
% Search for pred_ids matching that p/f, name, arity,
|
||||||
|
% and succeed if the method definition p/f, name, and
|
||||||
|
% arity matches at least one of the methods from the
|
||||||
|
% class interface
|
||||||
|
adjust_func_arity(MethodPredOrFunc, MethodArity,
|
||||||
|
MethodPredArity),
|
||||||
|
predicate_table_search_pf_sym_arity(PredTable,
|
||||||
|
MethodPredOrFunc, MethodName, MethodPredArity,
|
||||||
|
MatchingPredIds),
|
||||||
|
some [PredId] (
|
||||||
|
list__member(PredId, MatchingPredIds),
|
||||||
|
list__member(PredId, ClassPredIds)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
list__filter(DefnIsOK, InstanceMethods, _OKInstanceMethods,
|
||||||
|
BogusInstanceMethods),
|
||||||
|
(
|
||||||
|
BogusInstanceMethods = []
|
||||||
|
->
|
||||||
|
Errors = Errors0
|
||||||
|
;
|
||||||
|
%
|
||||||
|
% There were one or more bogus methods.
|
||||||
|
% Construct an appropriate error message.
|
||||||
|
%
|
||||||
|
ClassId = class_id(ClassName, ClassArity),
|
||||||
|
prog_out__sym_name_to_string(ClassName,
|
||||||
|
ClassNameString),
|
||||||
|
string__int_to_string(ClassArity, ClassArityString),
|
||||||
|
string__append_list([
|
||||||
|
"In instance declaration for `",
|
||||||
|
ClassNameString, "/", ClassArityString, "': ",
|
||||||
|
"incorrect method name(s): "],
|
||||||
|
ErrorMsgStart),
|
||||||
|
BogusInstanceMethodNames = list__map(format_method_name,
|
||||||
|
BogusInstanceMethods),
|
||||||
|
error_util__list_to_pieces(BogusInstanceMethodNames,
|
||||||
|
ErrorMsgBody0),
|
||||||
|
ErrorMsgBody = list__append(ErrorMsgBody0, [words(".")]),
|
||||||
|
NewError = Context - [words(ErrorMsgStart) | ErrorMsgBody],
|
||||||
|
Errors = [NewError | Errors0]
|
||||||
|
).
|
||||||
|
|
||||||
|
:- func format_method_name(instance_method) = string.
|
||||||
|
format_method_name(Method) = StringName :-
|
||||||
|
Method = instance_method(PredOrFunc, Name, _Defn, Arity, _Context),
|
||||||
|
adjust_func_arity(PredOrFunc, Arity, PredArity),
|
||||||
|
hlds_out__simple_call_id_to_string(
|
||||||
|
PredOrFunc - Name/PredArity, StringName).
|
||||||
|
|
||||||
%----------------------------------------------------------------------------%
|
%----------------------------------------------------------------------------%
|
||||||
|
|
||||||
:- type instance_check_info
|
:- type instance_check_info
|
||||||
@@ -280,6 +319,10 @@ check_class_instance(ClassId, SuperClasses, Vars, ClassInterface, ClassVarSet,
|
|||||||
% introduced pred
|
% introduced pred
|
||||||
% should be given.
|
% should be given.
|
||||||
arity, % Arity of the method.
|
arity, % Arity of the method.
|
||||||
|
% (For funcs, this is
|
||||||
|
% the original arity,
|
||||||
|
% not the arity as a
|
||||||
|
% predicate.)
|
||||||
existq_tvars, % Existentially quant.
|
existq_tvars, % Existentially quant.
|
||||||
% type variables
|
% type variables
|
||||||
list(type), % Expected types of
|
list(type), % Expected types of
|
||||||
@@ -344,6 +387,7 @@ check_instance_pred(ClassId, ClassVars, ClassInterface, PredId,
|
|||||||
MethodName = qualified(PredModule, MethodName0),
|
MethodName = qualified(PredModule, MethodName0),
|
||||||
pred_info_arity(PredInfo, PredArity),
|
pred_info_arity(PredInfo, PredArity),
|
||||||
pred_info_get_is_pred_or_func(PredInfo, PredOrFunc),
|
pred_info_get_is_pred_or_func(PredInfo, PredOrFunc),
|
||||||
|
adjust_func_arity(PredOrFunc, Arity, PredArity),
|
||||||
pred_info_procedures(PredInfo, ProcTable),
|
pred_info_procedures(PredInfo, ProcTable),
|
||||||
list__map(
|
list__map(
|
||||||
lambda([TheProcId::in, ModesAndDetism::out] is det,
|
lambda([TheProcId::in, ModesAndDetism::out] is det,
|
||||||
@@ -362,11 +406,11 @@ check_instance_pred(ClassId, ClassVars, ClassInterface, PredId,
|
|||||||
|
|
||||||
% Work out the name of the predicate that we will generate
|
% Work out the name of the predicate that we will generate
|
||||||
% to check this instance method.
|
% to check this instance method.
|
||||||
make_introduced_pred_name(ClassId, MethodName, PredArity,
|
make_introduced_pred_name(ClassId, MethodName, Arity,
|
||||||
InstanceTypes, PredName),
|
InstanceTypes, PredName),
|
||||||
|
|
||||||
Info0 = instance_method_info(ModuleInfo0, QualInfo0, PredName,
|
Info0 = instance_method_info(ModuleInfo0, QualInfo0, PredName,
|
||||||
PredArity, ExistQVars, ArgTypes, ClassContext, ArgModes,
|
Arity, ExistQVars, ArgTypes, ClassContext, ArgModes,
|
||||||
Errors0, ArgTypeVars, Status, PredOrFunc),
|
Errors0, ArgTypeVars, Status, PredOrFunc),
|
||||||
|
|
||||||
check_instance_pred_procs(ClassId, ClassVars, MethodName, Markers,
|
check_instance_pred_procs(ClassId, ClassVars, MethodName, Markers,
|
||||||
@@ -374,7 +418,7 @@ check_instance_pred(ClassId, ClassVars, ClassInterface, PredId,
|
|||||||
Info0, Info, IO0, IO),
|
Info0, Info, IO0, IO),
|
||||||
|
|
||||||
Info = instance_method_info(ModuleInfo, QualInfo, _PredName,
|
Info = instance_method_info(ModuleInfo, QualInfo, _PredName,
|
||||||
_PredArity, _ExistQVars, _ArgTypes, _ClassContext, _ArgModes,
|
_Arity, _ExistQVars, _ArgTypes, _ClassContext, _ArgModes,
|
||||||
Errors, _ArgTypeVars, _Status, _PredOrFunc),
|
Errors, _ArgTypeVars, _Status, _PredOrFunc),
|
||||||
|
|
||||||
InstanceCheckInfo = instance_check_info(InstanceDefn,
|
InstanceCheckInfo = instance_check_info(InstanceDefn,
|
||||||
@@ -395,11 +439,11 @@ check_instance_pred_procs(ClassId, ClassVars, MethodName, Markers,
|
|||||||
InstanceConstraints, InstanceTypes,
|
InstanceConstraints, InstanceTypes,
|
||||||
InstanceBody, MaybeInstancePredProcs,
|
InstanceBody, MaybeInstancePredProcs,
|
||||||
InstanceVarSet, H),
|
InstanceVarSet, H),
|
||||||
Info0 = instance_method_info(ModuleInfo, QualInfo, PredName, PredArity,
|
Info0 = instance_method_info(ModuleInfo, QualInfo, PredName, Arity,
|
||||||
ExistQVars, ArgTypes, ClassContext, ArgModes, Errors0,
|
ExistQVars, ArgTypes, ClassContext, ArgModes, Errors0,
|
||||||
ArgTypeVars, Status, PredOrFunc),
|
ArgTypeVars, Status, PredOrFunc),
|
||||||
get_matching_instance_names(InstanceBody, PredOrFunc, MethodName,
|
get_matching_instance_defns(InstanceBody, PredOrFunc, MethodName,
|
||||||
PredArity, MatchingInstanceMethods),
|
Arity, MatchingInstanceMethods),
|
||||||
(
|
(
|
||||||
MatchingInstanceMethods = [InstanceMethod]
|
MatchingInstanceMethods = [InstanceMethod]
|
||||||
->
|
->
|
||||||
@@ -435,22 +479,16 @@ check_instance_pred_procs(ClassId, ClassVars, MethodName, Markers,
|
|||||||
;
|
;
|
||||||
MatchingInstanceMethods = [I1, I2 | Is]
|
MatchingInstanceMethods = [I1, I2 | Is]
|
||||||
->
|
->
|
||||||
% one kind of error
|
%
|
||||||
|
% duplicate method definition error
|
||||||
|
%
|
||||||
OrderedInstanceMethods = OrderedInstanceMethods0,
|
OrderedInstanceMethods = OrderedInstanceMethods0,
|
||||||
InstanceDefn = InstanceDefn0,
|
InstanceDefn = InstanceDefn0,
|
||||||
ClassId = class_id(ClassName, _ClassArity),
|
ClassId = class_id(ClassName, _ClassArity),
|
||||||
prog_out__sym_name_to_string(MethodName, MethodNameString),
|
prog_out__sym_name_to_string(MethodName, MethodNameString),
|
||||||
prog_out__sym_name_to_string(ClassName, ClassNameString),
|
prog_out__sym_name_to_string(ClassName, ClassNameString),
|
||||||
(
|
pred_or_func_to_string(PredOrFunc, PredOrFuncString),
|
||||||
PredOrFunc = predicate,
|
string__int_to_string(Arity, ArityString),
|
||||||
PredOrFuncString = "predicate",
|
|
||||||
RealPredArity = PredArity
|
|
||||||
;
|
|
||||||
PredOrFunc = function,
|
|
||||||
PredOrFuncString = "function",
|
|
||||||
RealPredArity = PredArity - 1
|
|
||||||
),
|
|
||||||
string__int_to_string(RealPredArity, PredArityString),
|
|
||||||
mercury_type_list_to_string(InstanceVarSet, InstanceTypes,
|
mercury_type_list_to_string(InstanceVarSet, InstanceTypes,
|
||||||
InstanceTypesString),
|
InstanceTypesString),
|
||||||
string__append_list([
|
string__append_list([
|
||||||
@@ -458,7 +496,7 @@ check_instance_pred_procs(ClassId, ClassVars, MethodName, Markers,
|
|||||||
ClassNameString, "(", InstanceTypesString, ")': ",
|
ClassNameString, "(", InstanceTypesString, ")': ",
|
||||||
"multiple implementations of type class ",
|
"multiple implementations of type class ",
|
||||||
PredOrFuncString, " method `",
|
PredOrFuncString, " method `",
|
||||||
MethodNameString, "/", PredArityString, "'."],
|
MethodNameString, "/", ArityString, "'."],
|
||||||
ErrorHeader),
|
ErrorHeader),
|
||||||
I1 = instance_method(_, _, _, _, I1Context),
|
I1 = instance_method(_, _, _, _, I1Context),
|
||||||
Heading =
|
Heading =
|
||||||
@@ -475,26 +513,20 @@ check_instance_pred_procs(ClassId, ClassVars, MethodName, Markers,
|
|||||||
list__append(SubsequentErrors, Heading, NewErrors),
|
list__append(SubsequentErrors, Heading, NewErrors),
|
||||||
list__append(NewErrors, Errors0, Errors),
|
list__append(NewErrors, Errors0, Errors),
|
||||||
Info = instance_method_info(ModuleInfo, QualInfo, PredName,
|
Info = instance_method_info(ModuleInfo, QualInfo, PredName,
|
||||||
PredArity, ExistQVars, ArgTypes, ClassContext,
|
Arity, ExistQVars, ArgTypes, ClassContext,
|
||||||
ArgModes, Errors, ArgTypeVars, Status, PredOrFunc),
|
ArgModes, Errors, ArgTypeVars, Status, PredOrFunc),
|
||||||
IO = IO0
|
IO = IO0
|
||||||
;
|
;
|
||||||
% another kind of error
|
%
|
||||||
|
% undefined method error
|
||||||
|
%
|
||||||
OrderedInstanceMethods = OrderedInstanceMethods0,
|
OrderedInstanceMethods = OrderedInstanceMethods0,
|
||||||
InstanceDefn = InstanceDefn0,
|
InstanceDefn = InstanceDefn0,
|
||||||
ClassId = class_id(ClassName, _ClassArity),
|
ClassId = class_id(ClassName, _ClassArity),
|
||||||
prog_out__sym_name_to_string(MethodName, MethodNameString),
|
prog_out__sym_name_to_string(MethodName, MethodNameString),
|
||||||
prog_out__sym_name_to_string(ClassName, ClassNameString),
|
prog_out__sym_name_to_string(ClassName, ClassNameString),
|
||||||
(
|
pred_or_func_to_string(PredOrFunc, PredOrFuncString),
|
||||||
PredOrFunc = predicate,
|
string__int_to_string(Arity, ArityString),
|
||||||
PredOrFuncString = "predicate",
|
|
||||||
RealPredArity = PredArity
|
|
||||||
;
|
|
||||||
PredOrFunc = function,
|
|
||||||
PredOrFuncString = "function",
|
|
||||||
RealPredArity = PredArity - 1
|
|
||||||
),
|
|
||||||
string__int_to_string(RealPredArity, PredArityString),
|
|
||||||
mercury_type_list_to_string(InstanceVarSet, InstanceTypes,
|
mercury_type_list_to_string(InstanceVarSet, InstanceTypes,
|
||||||
InstanceTypesString),
|
InstanceTypesString),
|
||||||
string__append_list([
|
string__append_list([
|
||||||
@@ -502,35 +534,74 @@ check_instance_pred_procs(ClassId, ClassVars, MethodName, Markers,
|
|||||||
ClassNameString, "(", InstanceTypesString, ")': ",
|
ClassNameString, "(", InstanceTypesString, ")': ",
|
||||||
"no implementation for type class ",
|
"no implementation for type class ",
|
||||||
PredOrFuncString, " method `",
|
PredOrFuncString, " method `",
|
||||||
MethodNameString, "/", PredArityString, "'."],
|
MethodNameString, "/", ArityString, "'."],
|
||||||
NewError),
|
NewError),
|
||||||
Errors = [InstanceContext - [words(NewError)] | Errors0],
|
Errors = [InstanceContext - [words(NewError)] | Errors0],
|
||||||
Info = instance_method_info(ModuleInfo, QualInfo, PredName,
|
Info = instance_method_info(ModuleInfo, QualInfo, PredName,
|
||||||
PredArity, ExistQVars, ArgTypes, ClassContext,
|
Arity, ExistQVars, ArgTypes, ClassContext,
|
||||||
ArgModes, Errors,
|
ArgModes, Errors,
|
||||||
ArgTypeVars, Status, PredOrFunc),
|
ArgTypeVars, Status, PredOrFunc),
|
||||||
IO = IO0
|
IO = IO0
|
||||||
).
|
).
|
||||||
|
|
||||||
:- pred get_matching_instance_names(instance_body, pred_or_func,
|
%
|
||||||
|
% Get all the instance definitions which match the specified
|
||||||
|
% predicate/function name/arity, with multiple clause definitions
|
||||||
|
% being combined into a single definition.
|
||||||
|
%
|
||||||
|
:- pred get_matching_instance_defns(instance_body, pred_or_func,
|
||||||
sym_name, arity, list(instance_method)).
|
sym_name, arity, list(instance_method)).
|
||||||
:- mode get_matching_instance_names(in, in, in, in, out) is det.
|
:- mode get_matching_instance_defns(in, in, in, in, out) is det.
|
||||||
|
|
||||||
get_matching_instance_names(InstanceBody, PredOrFunc, MethodName,
|
get_matching_instance_defns(abstract, _, _, _, []).
|
||||||
MethodArity0, MatchingInstanceMethods) :-
|
get_matching_instance_defns(concrete(InstanceMethods), PredOrFunc, MethodName,
|
||||||
adjust_func_arity(PredOrFunc, MethodArity, MethodArity0),
|
MethodArity, ResultList) :-
|
||||||
solutions(
|
%
|
||||||
(pred(Method::out) is nondet :-
|
% First find the instance method definitions that match this
|
||||||
InstanceBody = concrete(InstanceMethods),
|
% predicate/function's name and arity
|
||||||
list__member(Method, InstanceMethods),
|
%
|
||||||
|
list__filter(
|
||||||
|
(pred(Method::in) is semidet :-
|
||||||
Method = instance_method(PredOrFunc,
|
Method = instance_method(PredOrFunc,
|
||||||
MethodName, _InstanceMethodDefn,
|
MethodName, _MethodDefn,
|
||||||
MethodArity, _Context)
|
MethodArity, _Context)
|
||||||
),
|
),
|
||||||
MatchingInstanceMethods).
|
InstanceMethods, MatchingMethods),
|
||||||
|
(
|
||||||
|
MatchingMethods = [First, _Second | _],
|
||||||
|
First = instance_method(_, _, _, _, FirstContext),
|
||||||
|
\+ (
|
||||||
|
list__member(DefnViaName, MatchingMethods),
|
||||||
|
DefnViaName = instance_method(_, _, name(_), _, _)
|
||||||
|
)
|
||||||
|
->
|
||||||
|
%
|
||||||
|
% If all of the instance method definitions for this
|
||||||
|
% pred/func are clauses, and there are more than one
|
||||||
|
% of them, then we must combine them all into a
|
||||||
|
% single definition.
|
||||||
|
%
|
||||||
|
MethodToClause = (pred(Method::in, Clauses::out) is semidet :-
|
||||||
|
Method = instance_method(_, _, Defn, _, _),
|
||||||
|
Defn = clauses(Clauses)),
|
||||||
|
list__filter_map(MethodToClause, MatchingMethods, ClausesList),
|
||||||
|
list__condense(ClausesList, FlattenedClauses),
|
||||||
|
CombinedMethod = instance_method(PredOrFunc,
|
||||||
|
MethodName, clauses(FlattenedClauses),
|
||||||
|
MethodArity, FirstContext),
|
||||||
|
ResultList = [CombinedMethod]
|
||||||
|
;
|
||||||
|
%
|
||||||
|
% If there are less than two matching method definitions,
|
||||||
|
% or if any of the instance method definitions is a method
|
||||||
|
% name, then we're done.
|
||||||
|
%
|
||||||
|
ResultList = MatchingMethods
|
||||||
|
).
|
||||||
|
|
||||||
% Just a bit simpler than using a pair of pairs
|
:- pred pred_or_func_to_string(pred_or_func::in, string::out) is det.
|
||||||
:- type triple(T1, T2, T3) ---> triple(T1, T2, T3).
|
pred_or_func_to_string(predicate, "predicate").
|
||||||
|
pred_or_func_to_string(function, "function").
|
||||||
|
|
||||||
:- pred produce_auxiliary_procs(list(tvar), pred_markers, list(type),
|
:- pred produce_auxiliary_procs(list(tvar), pred_markers, list(type),
|
||||||
list(class_constraint), tvarset, instance_proc_def, prog_context,
|
list(class_constraint), tvarset, instance_proc_def, prog_context,
|
||||||
@@ -545,7 +616,7 @@ produce_auxiliary_procs(ClassVars, Markers0,
|
|||||||
InstanceProcIds, Info0, Info, IO0, IO) :-
|
InstanceProcIds, Info0, Info, IO0, IO) :-
|
||||||
|
|
||||||
Info0 = instance_method_info(ModuleInfo0, QualInfo0, PredName,
|
Info0 = instance_method_info(ModuleInfo0, QualInfo0, PredName,
|
||||||
PredArity, ExistQVars0, ArgTypes0, ClassContext0, ArgModes,
|
Arity, ExistQVars0, ArgTypes0, ClassContext0, ArgModes,
|
||||||
Errors, ArgTypeVars0, Status0, PredOrFunc),
|
Errors, ArgTypeVars0, Status0, PredOrFunc),
|
||||||
|
|
||||||
% Rename the instance variables apart from the class variables
|
% Rename the instance variables apart from the class variables
|
||||||
@@ -590,6 +661,7 @@ produce_auxiliary_procs(ClassVars, Markers0,
|
|||||||
module_info_globals(ModuleInfo0, Globals),
|
module_info_globals(ModuleInfo0, Globals),
|
||||||
globals__lookup_string_option(Globals, aditi_user, User),
|
globals__lookup_string_option(Globals, aditi_user, User),
|
||||||
|
|
||||||
|
adjust_func_arity(PredOrFunc, Arity, PredArity),
|
||||||
produce_instance_method_clauses(InstancePredDefn, PredOrFunc,
|
produce_instance_method_clauses(InstancePredDefn, PredOrFunc,
|
||||||
PredArity, ArgTypes, Markers, Context, ClausesInfo,
|
PredArity, ArgTypes, Markers, Context, ClausesInfo,
|
||||||
ModuleInfo0, ModuleInfo1, QualInfo0, QualInfo, IO0, IO),
|
ModuleInfo0, ModuleInfo1, QualInfo0, QualInfo, IO0, IO),
|
||||||
@@ -629,7 +701,7 @@ produce_auxiliary_procs(ClassVars, Markers0,
|
|||||||
module_info_set_predicate_table(ModuleInfo1, PredicateTable,
|
module_info_set_predicate_table(ModuleInfo1, PredicateTable,
|
||||||
ModuleInfo),
|
ModuleInfo),
|
||||||
|
|
||||||
Info = instance_method_info(ModuleInfo, QualInfo, PredName, PredArity,
|
Info = instance_method_info(ModuleInfo, QualInfo, PredName, Arity,
|
||||||
ExistQVars, ArgTypes, ClassContext, ArgModes, Errors,
|
ExistQVars, ArgTypes, ClassContext, ArgModes, Errors,
|
||||||
ArgTypeVars, Status, PredOrFunc).
|
ArgTypeVars, Status, PredOrFunc).
|
||||||
|
|
||||||
@@ -651,14 +723,14 @@ apply_substitution_to_var_list(Vars0, RenameSubst, Vars) :-
|
|||||||
sym_name).
|
sym_name).
|
||||||
:- mode make_introduced_pred_name(in, in, in, in, out) is det.
|
:- mode make_introduced_pred_name(in, in, in, in, out) is det.
|
||||||
|
|
||||||
make_introduced_pred_name(ClassId, MethodName, PredArity,
|
make_introduced_pred_name(ClassId, MethodName, Arity,
|
||||||
InstanceTypes, PredName) :-
|
InstanceTypes, PredName) :-
|
||||||
ClassId = class_id(ClassName, _ClassArity),
|
ClassId = class_id(ClassName, _ClassArity),
|
||||||
prog_out__sym_name_to_string(ClassName, "__", ClassNameString),
|
prog_out__sym_name_to_string(ClassName, "__", ClassNameString),
|
||||||
prog_out__sym_name_to_string(MethodName, "__", MethodNameString),
|
prog_out__sym_name_to_string(MethodName, "__", MethodNameString),
|
||||||
% Perhaps we should include the pred arity in this mangled
|
% Perhaps we should include the arity in this mangled
|
||||||
% string?
|
% string?
|
||||||
string__int_to_string(PredArity, PredArityString),
|
string__int_to_string(Arity, ArityString),
|
||||||
base_typeclass_info__make_instance_string(InstanceTypes,
|
base_typeclass_info__make_instance_string(InstanceTypes,
|
||||||
InstanceString),
|
InstanceString),
|
||||||
string__append_list(
|
string__append_list(
|
||||||
@@ -666,7 +738,7 @@ make_introduced_pred_name(ClassId, MethodName, PredArity,
|
|||||||
ClassNameString, "__",
|
ClassNameString, "__",
|
||||||
InstanceString, "____",
|
InstanceString, "____",
|
||||||
MethodNameString, "_",
|
MethodNameString, "_",
|
||||||
PredArityString],
|
ArityString],
|
||||||
PredNameString),
|
PredNameString),
|
||||||
PredName = unqualified(PredNameString).
|
PredName = unqualified(PredNameString).
|
||||||
|
|
||||||
|
|||||||
@@ -3587,11 +3587,17 @@ define ordinary predicates or functions (@pxref{Items}), and so they
|
|||||||
can be facts, rules, or DCG rules. The only difference is that in instance
|
can be facts, rules, or DCG rules. The only difference is that in instance
|
||||||
declarations, clauses are separated by commas rather than being terminated
|
declarations, clauses are separated by commas rather than being terminated
|
||||||
by periods, and so rules and DCG rules in instance declarations must
|
by periods, and so rules and DCG rules in instance declarations must
|
||||||
normally be enclosed in parentheses.
|
normally be enclosed in parentheses. As with ordinary predicates,
|
||||||
|
you can have more than one clause for each method. The clauses must
|
||||||
|
satisfy the declared type, modes, determinism and purity for the
|
||||||
|
method, after the types of the arguments in the instance declaration
|
||||||
|
have been substituted in place of the parameters in the type class
|
||||||
|
declaration.
|
||||||
|
|
||||||
Currently, each method must be defined by a single clause;
|
These two ways are mutually exclusive: each method must be defined
|
||||||
we do not permit using more than than one clause per method.
|
either by a single naming definition (using the @samp{pred(@dots{}) is
|
||||||
(We hope to lift this restriction at some point in the future.)
|
@var{predname}} or @samp{func(@dots{}) is @var{funcname}} form),
|
||||||
|
or by a set of one or more clauses, but not both.
|
||||||
|
|
||||||
Here's an example of an instance declaration and the different kinds
|
Here's an example of an instance declaration and the different kinds
|
||||||
of method definitions that it can contain:
|
of method definitions that it can contain:
|
||||||
@@ -3602,6 +3608,7 @@ of method definitions that it can contain:
|
|||||||
func method2(T) = int,
|
func method2(T) = int,
|
||||||
pred method3(T::in, int::out) is det
|
pred method3(T::in, int::out) is det
|
||||||
pred method4(T::in, io__state::di, io__state::uo) is det
|
pred method4(T::in, io__state::di, io__state::uo) is det
|
||||||
|
func method5(bool, T) = T
|
||||||
].
|
].
|
||||||
|
|
||||||
:- instance foo(int) where [
|
:- instance foo(int) where [
|
||||||
@@ -3615,7 +3622,11 @@ of method definitions that it can contain:
|
|||||||
(method3(X, Y) :- Y = X + 2),
|
(method3(X, Y) :- Y = X + 2),
|
||||||
|
|
||||||
% method defined by a DCG rule
|
% method defined by a DCG rule
|
||||||
(method4(X) --> io__print(X), io__nl)
|
(method4(X) --> io__print(X), io__nl),
|
||||||
|
|
||||||
|
% method defined by multiple clauses
|
||||||
|
method5(no, _) = 0,
|
||||||
|
(method5(yes, X) = Y :- X + Y = 0)
|
||||||
].
|
].
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ SINGLEMODULE_SOURCES= \
|
|||||||
type_loop.m \
|
type_loop.m \
|
||||||
type_mismatch.m \
|
type_mismatch.m \
|
||||||
type_vars.m \
|
type_vars.m \
|
||||||
|
typeclass_bogus_method.m \
|
||||||
typeclass_mode.m \
|
typeclass_mode.m \
|
||||||
typeclass_test_1.m \
|
typeclass_test_1.m \
|
||||||
typeclass_test_2.m \
|
typeclass_test_2.m \
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ tc_err1.m:028: In instance declaration for `tc_err1:actions(tc_err1:pstate)':
|
|||||||
tc_err1.m:028: no implementation for type class predicate method
|
tc_err1.m:028: no implementation for type class predicate method
|
||||||
tc_err1.m:028: `tc_err1:handle_typedefs/3'.
|
tc_err1.m:028: `tc_err1:handle_typedefs/3'.
|
||||||
tc_err1.m:028: In instance declaration for `tc_err1:actions/1': incorrect
|
tc_err1.m:028: In instance declaration for `tc_err1:actions/1': incorrect
|
||||||
tc_err1.m:028: method name(s).
|
tc_err1.m:028: method name(s): predicate `tc_err1:handle_typedefs/2' .
|
||||||
For more information, try recompiling with `-E'.
|
For more information, try recompiling with `-E'.
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ tc_err2.m:034: In instance declaration for `tc_err2:actions(tc_err2:pstate)':
|
|||||||
tc_err2.m:034: no implementation for type class predicate method
|
tc_err2.m:034: no implementation for type class predicate method
|
||||||
tc_err2.m:034: `tc_err2:handle_typedefs/3'.
|
tc_err2.m:034: `tc_err2:handle_typedefs/3'.
|
||||||
tc_err2.m:034: In instance declaration for `tc_err2:actions/1': incorrect
|
tc_err2.m:034: In instance declaration for `tc_err2:actions/1': incorrect
|
||||||
tc_err2.m:034: method name(s).
|
tc_err2.m:034: method name(s): predicate `tc_err2:handle_typedefs/2' .
|
||||||
For more information, try recompiling with `-E'.
|
For more information, try recompiling with `-E'.
|
||||||
|
|||||||
21
tests/invalid/typeclass_bogus_method.err_exp
Normal file
21
tests/invalid/typeclass_bogus_method.err_exp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
typeclass_bogus_method.m:022: In instance declaration for
|
||||||
|
typeclass_bogus_method.m:022: `typeclass_bogus_method:tc1/1': incorrect
|
||||||
|
typeclass_bogus_method.m:022: method name(s): function
|
||||||
|
typeclass_bogus_method.m:022: `typeclass_bogus_method:bar/2' .
|
||||||
|
typeclass_bogus_method.m:026: In instance declaration for
|
||||||
|
typeclass_bogus_method.m:026: `typeclass_bogus_method:tc2/1': incorrect
|
||||||
|
typeclass_bogus_method.m:026: method name(s): function
|
||||||
|
typeclass_bogus_method.m:026: `typeclass_bogus_method:baz/1' .
|
||||||
|
typeclass_bogus_method.m:029: In instance declaration for
|
||||||
|
typeclass_bogus_method.m:029: `typeclass_bogus_method:tc3(int)': no
|
||||||
|
typeclass_bogus_method.m:029: implementation for type class function method
|
||||||
|
typeclass_bogus_method.m:029: `typeclass_bogus_method:foo3/1'.
|
||||||
|
typeclass_bogus_method.m:029: In instance declaration for
|
||||||
|
typeclass_bogus_method.m:029: `typeclass_bogus_method:tc3/1': incorrect
|
||||||
|
typeclass_bogus_method.m:029: method name(s): function
|
||||||
|
typeclass_bogus_method.m:029: `typeclass_bogus_method:foo5/1' .
|
||||||
|
typeclass_bogus_method.m:033: In instance declaration for
|
||||||
|
typeclass_bogus_method.m:033: `typeclass_bogus_method:tc4/1': incorrect
|
||||||
|
typeclass_bogus_method.m:033: method name(s): function
|
||||||
|
typeclass_bogus_method.m:033: `typeclass_bogus_method:foo5/1' .
|
||||||
|
For more information, try recompiling with `-E'.
|
||||||
35
tests/invalid/typeclass_bogus_method.m
Normal file
35
tests/invalid/typeclass_bogus_method.m
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
:- module typeclass_bogus_method.
|
||||||
|
:- interface.
|
||||||
|
|
||||||
|
:- typeclass tc1(T) where [ func foo1(T) = int ].
|
||||||
|
:- typeclass tc2(T) where [ func foo2(T) = int ].
|
||||||
|
:- typeclass tc3(T) where [ func foo3(T) = int ].
|
||||||
|
:- typeclass tc4(T) where [ func foo4(T) = int ].
|
||||||
|
:- typeclass tc5(T) where [ func foo5(T) = int ].
|
||||||
|
|
||||||
|
:- instance tc1(int).
|
||||||
|
:- instance tc2(int).
|
||||||
|
:- instance tc3(int).
|
||||||
|
:- instance tc4(int).
|
||||||
|
|
||||||
|
:- implementation.
|
||||||
|
:- import_module int.
|
||||||
|
|
||||||
|
:- func incr(int) = int.
|
||||||
|
incr(X) = X + 1.
|
||||||
|
|
||||||
|
:- instance tc1(int) where [
|
||||||
|
func(foo1/1) is incr,
|
||||||
|
func(bar/2) is incr
|
||||||
|
].
|
||||||
|
:- instance tc2(int) where [
|
||||||
|
func(foo2/1) is incr,
|
||||||
|
baz(X) = X + 1
|
||||||
|
].
|
||||||
|
:- instance tc3(int) where [
|
||||||
|
func(foo5/1) is incr
|
||||||
|
].
|
||||||
|
:- instance tc4(int) where [
|
||||||
|
func(foo4/1) is incr,
|
||||||
|
func(foo5/1) is incr
|
||||||
|
].
|
||||||
@@ -4,5 +4,5 @@ typeclass_test_3.m:014: implementation for type class function method
|
|||||||
typeclass_test_3.m:014: `typeclass_test_3:type_num/1'.
|
typeclass_test_3.m:014: `typeclass_test_3:type_num/1'.
|
||||||
typeclass_test_3.m:014: In instance declaration for
|
typeclass_test_3.m:014: In instance declaration for
|
||||||
typeclass_test_3.m:014: `typeclass_test_3:numbered_type/1': incorrect method
|
typeclass_test_3.m:014: `typeclass_test_3:numbered_type/1': incorrect method
|
||||||
typeclass_test_3.m:014: name(s).
|
typeclass_test_3.m:014: name(s): function `typeclass_test_3:type_num/0' .
|
||||||
For more information, try recompiling with `-E'.
|
For more information, try recompiling with `-E'.
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ typeclass_test_4.m:014: implementation for type class function method
|
|||||||
typeclass_test_4.m:014: `typeclass_test_4:type_num/1'.
|
typeclass_test_4.m:014: `typeclass_test_4:type_num/1'.
|
||||||
typeclass_test_4.m:014: In instance declaration for
|
typeclass_test_4.m:014: In instance declaration for
|
||||||
typeclass_test_4.m:014: `typeclass_test_4:numbered_type/1': incorrect method
|
typeclass_test_4.m:014: `typeclass_test_4:numbered_type/1': incorrect method
|
||||||
typeclass_test_4.m:014: name(s).
|
typeclass_test_4.m:014: name(s): function `typeclass_test_4:type_num/0' .
|
||||||
For more information, try recompiling with `-E'.
|
For more information, try recompiling with `-E'.
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ typeclass_test_5.m:015: multiple implementations of type class predicate
|
|||||||
typeclass_test_5.m:015: method `typeclass_test_5:p/1'.
|
typeclass_test_5.m:015: method `typeclass_test_5:p/1'.
|
||||||
typeclass_test_5.m:016: First definition appears here.
|
typeclass_test_5.m:016: First definition appears here.
|
||||||
typeclass_test_5.m:017: Subsequent definition appears here.
|
typeclass_test_5.m:017: Subsequent definition appears here.
|
||||||
typeclass_test_5.m:015: In instance declaration for `typeclass_test_5:c2/1':
|
|
||||||
typeclass_test_5.m:015: incorrect method name(s).
|
|
||||||
typeclass_test_5.m:015: In instance declaration for `typeclass_test_5:c2(int)':
|
typeclass_test_5.m:015: In instance declaration for `typeclass_test_5:c2(int)':
|
||||||
typeclass_test_5.m:015: superclass constraint(s) not satisfied:
|
typeclass_test_5.m:015: superclass constraint(s) not satisfied:
|
||||||
typeclass_test_5.m:015: `typeclass_test_5:c1(int)'.
|
typeclass_test_5.m:015: `typeclass_test_5:c1(int)'.
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ typeclass_test_9.m:010: Error: multiply defined (or overlapping) instance
|
|||||||
typeclass_test_9.m:010: declarations for class `typeclass_test_9:foo/1'.
|
typeclass_test_9.m:010: declarations for class `typeclass_test_9:foo/1'.
|
||||||
typeclass_test_9.m:007: Previous instance declaration was here.
|
typeclass_test_9.m:007: Previous instance declaration was here.
|
||||||
typeclass_test_9.m:013: In instance declaration for `typeclass_test_9:bar/1':
|
typeclass_test_9.m:013: In instance declaration for `typeclass_test_9:bar/1':
|
||||||
typeclass_test_9.m:013: incorrect method name(s).
|
typeclass_test_9.m:013: incorrect method name(s): predicate
|
||||||
|
typeclass_test_9.m:013: `typeclass_test_9:p/0' .
|
||||||
typeclass_test_9.m:018: In instance declaration for `typeclass_test_9:baz/1':
|
typeclass_test_9.m:018: In instance declaration for `typeclass_test_9:baz/1':
|
||||||
typeclass_test_9.m:018: incorrect method name(s).
|
typeclass_test_9.m:018: incorrect method name(s): predicate
|
||||||
|
typeclass_test_9.m:018: `typeclass_test_9:r/0' .
|
||||||
For more information, try recompiling with `-E'.
|
For more information, try recompiling with `-E'.
|
||||||
|
|||||||
Reference in New Issue
Block a user