Files
mercury/compiler/make_hlds_error.m
Zoltan Somogyi cc42c8fac5 Switch to using error_util to generate error message during the process of
Estimated hours taken: 40
Branches: main

Switch to using error_util to generate error message during the process of
converting terms to prog_items.

In many predicates, we used to return error messages as a string/term pair,
with the string being the error message and a term, which both provided
the context and was printed after the message. We now return error indications
as lists of error_specs. These include a printout of the relevant term only
if this helps users understand the nature or the location of the error.
To make the printouts easier to understand we print variable names in them
using the applicable varsets. (The old version of the compiler used to print
each error term long after it lost track of the right varset, and thus used
a dummy varset that yielded error messages referring to _1, _2 etc instead
of the variable names used by the programmer.)

Sometimes the callers of some parse predicates prepended other strings
indicating the context of the error in front of the error string.
This diff changes things so that now the caller instead passes a list
of format components describing the context to the predicates that construct
the error_specs.

In some places, simplify the code, e.g. by factoring out common code, and by
inlining some auxiliary predicates (we used to need these auxiliary predicates
for indexing when we executed the compiler using Prolog, but those days are
long past).

Mark with XXXs places where I think the error messages or their contexts
could be improved, and places where the structure of the code could be
improved.

compiler/prog_io_util.m:
	Change the representation of the maybeN types to use error_spec lists.

compiler/prog_io.m:
compiler/prog_io_dcg.m:
compiler/prog_io_goal.m:
compiler/prog_io_pragma.m:
compiler/prog_io_typeclass.m:
compiler/prog_io_util.m:
	Change the way we generate error messages along the lines described
	at the top.

	In several cases, this required adding extra arguments (varsets,
	context descriptions) to predicates for use in error messages.

	Some of these predicates were also used in contexts where the caller
	was interested only in success, and would ignore any error messages.
	In these cases, add a version of the predicate that does not require
	the extra arguments, and which is semidet (to allow the caller to
	avoid a test for ok).

compiler/error_util.m:
	Add a mechanism for changing the case of the next format_component,
	to allow an error message to be appended to a list of format_components
	providing the context that generates good-looking output whether or not
	that context is empty.

	Replace some bools with purpose-specific types.

	Make sort_error_specs internal to the module, since outside modules
	should never need to use it.

	Use cords instead of reversed lists to simplify some parts of the
	internal implementation.

compiler/mercury_to_mercury.m:
	Provide a mechanism to print out terms only if they aren't too big,
	for use in our error messages.

compiler/prog_item.m:
	Delete the message_list type, and note a future improvement.

compiler/prog_out.m:
	Delete the predicates for printing message_lists.

compiler/intermod.m:
compiler/modules.m:
	Change the way we print out error messages along the lines described
	at the top.

compiler/add_clause.m:
compiler/field_access.m:
compiler/recompilation.check.m:
compiler/recompilation.version.m:
compiler/superhomogeneous.m:
	Conform to the changes above by modifying how we generate error
	messages.

compiler/add_class.m:
compiler/add_pragma.m:
compiler/check_typeclass.m:
compiler/common.m:
compiler/make.module_dep_file.m:
compiler/make_hlds_error.m:
compiler/make_hlds_passes.m:
compiler/mercury_compile.m:
compiler/mode_errors.m:
compiler/modes.m:
compiler/options_file.m:
compiler/prog_ctgc.m:
compiler/prog_event.m:
compiler/purity.m:
compiler/trans_opt.m:
compiler/typecheck.m:
	Trivial updates to conform to the changes above.

compiler/prog_data.m:
	Add some field names and access functions for use in the modules above.

library/list.m:
	Add list.contains, which is list.member with the arguments reversed
	to make it possibly to partially apply it.

tests/invalid/bad_finalise_decl.err_exp:
tests/invalid/bad_initialise_decl.err_exp:
tests/invalid/bad_mutable.err_exp:
tests/invalid/bigtest.err_exp:
tests/invalid/conflicting_fs.err_exp:
tests/invalid/constrained_poly_insts.err_exp:
tests/invalid/errors.err_exp:
tests/invalid/func_errors.err_exp:
tests/invalid/fundeps_unbound_in_ctor.err_exp:
tests/invalid/fundeps_vars.err_exp:
tests/invalid/impl_def_literal_syntax.err_exp:
tests/invalid/inst_list_dup.err_exp:
tests/invalid/invalid_typeclass.err_exp:
tests/invalid/kind.err_exp:
tests/invalid/null_char.err_exp:
tests/invalid/pragma_source_file.err_exp:
tests/invalid/predmode.err_exp:
tests/invalid/reserve_tag.err_exp:
tests/invalid/some.err_exp:
tests/invalid/specified.err_exp:
tests/invalid/trace_goal_env.err_exp:
tests/invalid/type_vars.err_exp:
tests/invalid/typeclass_test_1.err_exp:
tests/invalid/typeclass_test_11.err_exp:
tests/invalid/typeclass_test_2.err_exp:
tests/invalid/unbound_type_vars.err_exp:
tests/invalid/unicode1.err_exp:
tests/invalid/unicode2.err_exp:
tests/invalid/uu_type.err_exp:
tests/invalid/vars_in_wrong_places.err_exp:
tests/invalid/with_type.err_exp:
tests/invalid/purity/purity_nonsense2.err_exp:
	Update the expected error messages.
2008-07-16 03:31:03 +00:00

215 lines
8.8 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 1993-2006, 2008 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: make_hlds_error.m.
%
% Utility predicates for writing out warning and error messages when
% building the HLDS. Error messages specific to a given submodule of
% make_hlds.m are in that specific submodule; this submodule is for error
% messages that are needed by more than one submodule.
%
%-----------------------------------------------------------------------------%
:- module hlds.make_hlds.make_hlds_error.
:- interface.
:- import_module hlds.hlds_pred.
:- import_module libs.globals.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.error_util.
:- import_module parse_tree.prog_data.
:- import_module bool.
:- import_module list.
%-----------------------------------------------------------------------------%
:- pred multiple_def_error(import_status::in, sym_name::in, int::in,
string::in, prog_context::in, prog_context::in, list(format_component)::in,
list(error_spec)::in, list(error_spec)::out) is det.
:- pred undefined_pred_or_func_error(sym_name::in, int::in, prog_context::in,
string::in, list(error_spec)::in, list(error_spec)::out) is det.
% Similar to undeclared_mode_error, but gives less information.
% XXX perhaps we should get rid of this, and change the callers to
% instead call undeclared_mode_error.
%
:- pred undefined_mode_error(sym_name::in, int::in, prog_context::in,
string::in, list(error_spec)::in, list(error_spec)::out) is det.
:- pred maybe_undefined_pred_error(globals::in, sym_name::in, int::in,
pred_or_func::in, import_status::in, bool::in, prog_context::in,
string::in, list(error_spec)::in, list(error_spec)::out) is det.
% Emit an error if something is exported. (Used to check for
% when things shouldn't be exported.)
%
:- pred error_if_exported(import_status::in, prog_context::in, string::in,
list(error_spec)::in, list(error_spec)::out) is det.
% Emit an error reporting that something should not have occurred in
% a module interface.
%
:- pred error_is_exported(prog_context::in, string::in,
list(error_spec)::in, list(error_spec)::out) is det.
%----------------------------------------------------------------------------%
%----------------------------------------------------------------------------%
:- implementation.
:- import_module check_hlds.mode_errors.
:- import_module hlds.hlds_error_util.
:- import_module libs.options.
:- import_module parse_tree.mercury_to_mercury.
:- import_module parse_tree.prog_mode.
:- import_module parse_tree.prog_out.
:- import_module varset.
%-----------------------------------------------------------------------------%
multiple_def_error(Status, Name, Arity, DefType, Context, OrigContext,
ExtraPieces, !Specs) :-
( Status = status_opt_imported ->
% We don't take care not to read the same declaration from multiple
% sources with inter-module optimization, so ignore multiple definition
% errors in the items read for inter-module optimization.
true
;
Pieces1 = [words("Error:"), fixed(DefType),
sym_name_and_arity(Name / Arity), words("multiply defined."), nl],
Pieces2 = [words("Here is the previous definition of"),
fixed(DefType), sym_name_and_arity(Name / Arity), suffix("."), nl],
Msg1 = simple_msg(Context, [always(Pieces1)]),
Msg2 = error_msg(yes(OrigContext), treat_as_first, 0,
[always(Pieces2)]),
(
ExtraPieces = [],
ExtraMsgs = []
;
ExtraPieces = [_ | _],
ExtraMsgs = [simple_msg(Context, [always(ExtraPieces)])]
),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds,
[Msg1, Msg2] ++ ExtraMsgs),
!:Specs = [Spec | !.Specs]
).
undefined_pred_or_func_error(Name, Arity, Context, Description, !Specs) :-
% This used to say `preceding' instead of `corresponding.'
% Which is more correct?
Pieces = [words("Error:"), words(Description), words("for"),
sym_name_and_arity(Name / Arity),
words("without corresponding `pred' or `func' declaration.")],
Msg = simple_msg(Context, [always(Pieces)]),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
!:Specs = [Spec | !.Specs].
undefined_mode_error(Name, Arity, Context, Description, !Specs) :-
Pieces = [words("Error:"), words(Description), words("for"),
sym_name_and_arity(Name / Arity),
words("specifies non-existent mode.")],
Msg = simple_msg(Context, [always(Pieces)]),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
!:Specs = [Spec | !.Specs].
% Similar to undefined_mode_error, but gives more information.
% XXX the documentation here should be somewhat less circular.
%
:- func undeclared_mode_error(list(mer_mode), prog_varset,
pred_id, pred_info, module_info, prog_context) = error_spec.
undeclared_mode_error(ModeList, VarSet, PredId, PredInfo, ModuleInfo, Context)
= Spec :-
PredIdPieces = describe_one_pred_name(ModuleInfo,
should_not_module_qualify, PredId),
strip_builtin_qualifiers_from_mode_list(ModeList, StrippedModeList),
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
Name = pred_info_name(PredInfo),
MaybeDet = no,
SubDeclStr = mercury_mode_subdecl_to_string(PredOrFunc,
varset.coerce(VarSet), unqualified(Name), StrippedModeList,
MaybeDet, Context),
MainPieces = [words("In clause for")] ++ PredIdPieces ++ [suffix(":"), nl,
words("error: mode annotation specifies undeclared mode"),
quote(SubDeclStr), suffix("."), nl],
ProcIds = pred_info_all_procids(PredInfo),
(
ProcIds = [],
VerbosePieces = [words("(There are no declared modes for this"),
p_or_f(PredOrFunc), suffix(".)"), nl]
;
ProcIds = [_ | _],
VerbosePieces = [words("The declared modes for this"),
p_or_f(PredOrFunc), words("are the following:"),
nl_indent_delta(1)] ++
component_list_to_line_pieces(
list.map(mode_decl_for_pred_info_to_pieces(PredInfo), ProcIds),
[]) ++
[nl_indent_delta(-1)]
),
Msg = simple_msg(Context,
[always(MainPieces), verbose_only(VerbosePieces)]),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]).
:- func mode_decl_for_pred_info_to_pieces(pred_info, proc_id)
= list(format_component).
mode_decl_for_pred_info_to_pieces(PredInfo, ProcId) =
[words(":- mode"), words(mode_decl_to_string(ProcId, PredInfo)),
suffix(".")].
% This is not considered an unconditional error anymore:
% if there is no `:- pred' or `:- func' declaration,
% and the declaration is local, and not a type class method,
% and the `--infer-types' option was specified,
% then we just add an implicit declaration for that predicate or
% function, marking it as one whose type will be inferred.
%
maybe_undefined_pred_error(Globals, Name, Arity, PredOrFunc, Status,
IsClassMethod, Context, Description, !Specs) :-
DefinedInThisModule = status_defined_in_this_module(Status),
IsExported = status_is_exported(Status),
globals.lookup_bool_option(Globals, infer_types, InferTypes),
(
DefinedInThisModule = yes,
IsExported = no,
IsClassMethod = no,
InferTypes = yes
->
true
;
Pieces = [words("Error:"), words(Description), words("for"),
simple_call(simple_call_id(PredOrFunc, Name, Arity)), nl,
words("without preceding"), quote(pred_or_func_to_str(PredOrFunc)),
words("declaration."), nl],
Msg = simple_msg(Context, [always(Pieces)]),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
!:Specs = [Spec | !.Specs]
).
error_is_exported(Context, Item, !Specs) :-
Pieces = [words("Error:"), fixed(Item), words("in module interface."), nl],
Msg = simple_msg(Context, [always(Pieces)]),
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
!:Specs = [Spec | !.Specs].
error_if_exported(Status, Context, Item, !Specs) :-
( Status = status_exported ->
error_is_exported(Context, Item, !Specs)
;
true
).
%----------------------------------------------------------------------------%
:- end_module make_hlds_error.
%----------------------------------------------------------------------------%