mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 06:47:17 +00:00
Estimated hours taken: 10
Branches: main
Improve error reporting for type class declarations in the situation where a
mode declaration for a method has been provided but there is no function or
predicate declaration for that method. Currently, this causes an internal
abort in the compiler.
Avoid another compiler abort in polymorphism.m when a type class method has two
duplicate mode declarations.
compiler/add_class.m:
Change the order in which we add type class declarations to the HLDS
so that we can detect and report situations where a type class method
has a mode declaration but no corresponding predicate or function
declaration. All of the predicate/function method declarations for a
particular typeclass need to be added before any mode declarations.
We can then check that there is a corresponding predicate/function
method declaration as each mode is added.
compiler/post_typecheck.m:
Have the post-typechecking pass indicate that an error has occurred if
we encounter indistinguishable mode declarations. This prevents
polymorphism being run if there are such mode declarations. This
avoids an internal abort in polymorphism.m when the mode declarations
in question are type class methods.
Unrelated change: s/io.state/io__state/ in an error message.
compiler/hlds_error_util.m:
When formatting predicate names, specifically identify type class
methods as such. e.g. instead of `predicate foo/1' we now
write them out as `type class predicate method foo/1'.
compiler/modecheck_call.m:
Fix a typo: s/identical/indentical/
compiler/prog_item.m:
Add the equivalence: class_methods == list(class_method).
compiler/equiv_type.m:
compiler/mercury_to_mercury.m:
compiler/module_qual.m:
compiler/prog_data.m:
compiler/prog_io_typeclass.m:
compiler/recompilation.version.m:
Minor changes to conform to the above.
tests/README:
Fix an line that exceeds 80 characters in length.
tests/invalid/Mmakefile:
Enable the test cases typeclass_mode_{2,3,4} since we now pass those
tests.
Delete a comment about `--split-c-files'. That option is no longer
supported.
tests/invalid/typeclass_mode_{2,3,4}.err_exp:
Add expected outputs for these test cases.
tests/invalid/invalid_main.err_exp:
The module qualifier in the expected output is now '.'.
tests/invalid/qualified_cons_id2.err_exp:
Delete the determinism error from the expected output. It won't show
up now as the above changes mean the compiler will abort before
determinism checking in this case.
tests/invalid/typeclass_dup_method_mode.{m,err_exp}:
Add a test case for the problem that causes an abort in the
polymorphism pass when a type class method has duplicate mode
declarations.
tests/invalid/typeclass_mode.err_exp:
Update the expected output to conform with the above changes. Also,
we no longer emit the spurious error message about missing clauses.
tests/recompilation/typeclass_method_pragma_r.err_exp.2:
Update to conform to the new naming of type class methods
in the error message.
243 lines
9.1 KiB
Mathematica
243 lines
9.1 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-2006 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: error_util.m.
|
|
% Main author: zs.
|
|
%
|
|
% This module contains code that can be helpful in the formatting of
|
|
% error messages. It builds upon parse_tree__error_util, and extends it
|
|
% with predicates that access HLDS data structures.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module hlds__hlds_error_util.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.error_util.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module list.
|
|
:- import_module std_util.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% Predicates to convert predicate and procedure names to strings
|
|
%
|
|
|
|
:- type should_module_qualify
|
|
---> should_module_qualify
|
|
; should_not_module_qualify.
|
|
|
|
:- func describe_one_pred_name(module_info, should_module_qualify, pred_id)
|
|
= list(format_component).
|
|
|
|
:- func describe_one_pred_info_name(should_module_qualify, pred_info)
|
|
= list(format_component).
|
|
|
|
:- func describe_one_pred_name_mode(module_info, should_module_qualify,
|
|
pred_id, inst_varset, list(mer_mode)) = list(format_component).
|
|
|
|
:- func describe_several_pred_names(module_info, should_module_qualify,
|
|
list(pred_id)) = list(format_component).
|
|
|
|
:- func describe_one_proc_name(module_info, should_module_qualify,
|
|
pred_proc_id) = list(format_component).
|
|
|
|
:- func describe_one_proc_name_mode(module_info, should_module_qualify,
|
|
pred_proc_id) = list(format_component).
|
|
|
|
:- func describe_several_proc_names(module_info, should_module_qualify,
|
|
list(pred_proc_id)) = list(format_component).
|
|
|
|
:- func describe_one_call_site(module_info, should_module_qualify,
|
|
pair(pred_proc_id, prog_context)) = list(format_component).
|
|
|
|
:- func describe_several_call_sites(module_info, should_module_qualify,
|
|
assoc_list(pred_proc_id, prog_context)) = list(format_component).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.mode_util.
|
|
:- import_module hlds.special_pred.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module libs.compiler_util.
|
|
:- import_module parse_tree.mercury_to_mercury.
|
|
:- import_module parse_tree.prog_mode.
|
|
:- import_module parse_tree.prog_out.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module int.
|
|
:- import_module string.
|
|
:- import_module list.
|
|
:- import_module term.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% NOTE: the code of this predicate duplicates the functionality of
|
|
% hlds_out__write_pred_id. Changes here should be made there as well.
|
|
%
|
|
describe_one_pred_name(Module, ShouldModuleQualify, PredId) = Pieces :-
|
|
module_info_pred_info(Module, PredId, PredInfo),
|
|
Pieces = describe_one_pred_info_name(ShouldModuleQualify, PredInfo).
|
|
|
|
describe_one_pred_info_name(ShouldModuleQualify, PredInfo) = Pieces :-
|
|
PredName = pred_info_name(PredInfo),
|
|
ModuleName = pred_info_module(PredInfo),
|
|
Arity = pred_info_orig_arity(PredInfo),
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
adjust_func_arity(PredOrFunc, OrigArity, Arity),
|
|
pred_info_get_markers(PredInfo, Markers),
|
|
pred_info_get_origin(PredInfo, Origin),
|
|
( Origin = special_pred(SpecialId - TypeCtor) ->
|
|
special_pred_description(SpecialId, Descr),
|
|
TypeCtor = TypeSymName - TypeArity,
|
|
( TypeArity = 0 ->
|
|
Pieces = [words(Descr), words("for type"),
|
|
sym_name(TypeSymName)]
|
|
;
|
|
Pieces = [words(Descr), words("for type constructor"),
|
|
sym_name(TypeSymName)]
|
|
)
|
|
; check_marker(Markers, class_instance_method) ->
|
|
Pieces = [words("type class method implementation")]
|
|
; pred_info_get_goal_type(PredInfo, promise(PromiseType)) ->
|
|
Pieces = [words("`" ++ promise_to_string(PromiseType) ++ "'"),
|
|
words("declaration")]
|
|
;
|
|
( check_marker(Markers, class_method) ->
|
|
Prefix = [
|
|
words("type class"),
|
|
pred_or_func(PredOrFunc),
|
|
words("method")
|
|
]
|
|
;
|
|
Prefix = [pred_or_func(PredOrFunc)]
|
|
),
|
|
string__int_to_string(OrigArity, ArityPart),
|
|
string__append_list([
|
|
"`",
|
|
module_qualification(ModuleName, ShouldModuleQualify),
|
|
PredName,
|
|
"/",
|
|
ArityPart,
|
|
"'"], SpecStr),
|
|
Pieces = Prefix ++ [fixed(SpecStr)]
|
|
).
|
|
|
|
describe_one_pred_name_mode(Module, ShouldModuleQualify, PredId, InstVarSet,
|
|
ArgModes0) = Pieces :-
|
|
module_info_pred_info(Module, PredId, PredInfo),
|
|
ModuleName = pred_info_module(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
Arity = pred_info_orig_arity(PredInfo),
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
list__length(ArgModes0, NumArgModes),
|
|
% We need to strip off the extra type_info arguments inserted at the
|
|
% front by polymorphism.m - we only want the last `Arity' of them.
|
|
( list__drop(NumArgModes - Arity, ArgModes0, ArgModes) ->
|
|
strip_builtin_qualifiers_from_mode_list(ArgModes, StrippedArgModes)
|
|
;
|
|
unexpected(this_file, "describe_one_pred_name_mode: bad argument list")
|
|
),
|
|
(
|
|
PredOrFunc = predicate,
|
|
ArgModesPart = arg_modes_to_string(InstVarSet, StrippedArgModes)
|
|
;
|
|
PredOrFunc = function,
|
|
pred_args_to_func_args(StrippedArgModes, FuncArgModes,
|
|
FuncRetMode),
|
|
ArgModesPart = arg_modes_to_string(InstVarSet, FuncArgModes)
|
|
++ " = " ++ mercury_mode_to_string(FuncRetMode, InstVarSet)
|
|
),
|
|
string__append_list([
|
|
"`",
|
|
module_qualification(ModuleName, ShouldModuleQualify),
|
|
PredName,
|
|
ArgModesPart,
|
|
"'"], Descr),
|
|
Pieces = [words(Descr)].
|
|
|
|
describe_several_pred_names(Module, ShouldModuleQualify, PredIds) = Pieces :-
|
|
PiecesList = list__map(describe_one_pred_name(Module, ShouldModuleQualify),
|
|
PredIds),
|
|
Pieces = component_lists_to_pieces(PiecesList).
|
|
|
|
describe_one_proc_name(Module, ShouldModuleQualify, proc(PredId, ProcId))
|
|
= Pieces :-
|
|
PredPieces = describe_one_pred_name(Module, ShouldModuleQualify, PredId),
|
|
proc_id_to_int(ProcId, ProcIdInt),
|
|
string__int_to_string(ProcIdInt, ProcIdStr),
|
|
Pieces = PredPieces ++ [words("mode"), words(ProcIdStr)].
|
|
|
|
describe_one_proc_name_mode(Module, ShouldModuleQualify, proc(PredId, ProcId))
|
|
= Pieces :-
|
|
module_info_pred_proc_info(Module, PredId, ProcId, _, ProcInfo),
|
|
proc_info_argmodes(ProcInfo, ArgModes),
|
|
proc_info_inst_varset(ProcInfo, InstVarSet),
|
|
Pieces = describe_one_pred_name_mode(Module, ShouldModuleQualify,
|
|
PredId, InstVarSet, ArgModes).
|
|
|
|
describe_several_proc_names(Module, ShouldModuleQualify, PPIds) = Pieces :-
|
|
PiecesList = list__map(describe_one_proc_name(Module, ShouldModuleQualify),
|
|
PPIds),
|
|
Pieces = component_lists_to_pieces(PiecesList).
|
|
|
|
describe_one_call_site(Module, ShouldModuleQualify, PPId - Context) = Pieces :-
|
|
ProcNamePieces = describe_one_proc_name(Module, ShouldModuleQualify,
|
|
PPId),
|
|
term__context_file(Context, FileName),
|
|
term__context_line(Context, LineNumber),
|
|
string__int_to_string(LineNumber, LineNumberStr),
|
|
Pieces = ProcNamePieces ++
|
|
[words("at"), fixed(FileName ++ ":" ++ LineNumberStr)].
|
|
|
|
describe_several_call_sites(Module, ShouldModuleQualify, Sites) = Pieces :-
|
|
PiecesList = list__map(describe_one_call_site(Module, ShouldModuleQualify),
|
|
Sites),
|
|
Pieces = component_lists_to_pieces(PiecesList).
|
|
|
|
:- func module_qualification(module_name, should_module_qualify) = string.
|
|
|
|
module_qualification(ModuleName, ShouldModuleQualify) = ModuleQualification :-
|
|
(
|
|
ShouldModuleQualify = should_module_qualify,
|
|
sym_name_to_string(ModuleName, ModuleNameString),
|
|
ModuleQualification = string__append(ModuleNameString, ".")
|
|
;
|
|
ShouldModuleQualify = should_not_module_qualify,
|
|
ModuleQualification = ""
|
|
).
|
|
|
|
:- func arg_modes_to_string(inst_varset, list(mer_mode)) = string.
|
|
|
|
arg_modes_to_string(InstVarSet, ArgModes) = Str :-
|
|
(
|
|
ArgModes = [],
|
|
Str = ""
|
|
;
|
|
ArgModes = [_ | _],
|
|
ArgsStr = mercury_mode_list_to_string(ArgModes, InstVarSet),
|
|
Str = "(" ++ ArgsStr ++ ")"
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "hlds_error_util.m".
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module hlds_error_util.
|
|
%-----------------------------------------------------------------------------%
|