Files
mercury/library/require.m
Zoltan Somogyi 66873a528a Fix the handling of status in add_pragma.m.
compiler/add_pragma.m:
    The status checks in this module used to check for only one
    of the four possible combinations of <is pragma exported, is the
    pred the pragma is for expored>, even though we may want to generate
    errors or warnings in three of those combinations. Fix this.

    If an ambiguous pragma applies to more than one predicate, handle
    the status checks of each separately.

    When adding fact table pragmas to the HLDS, replace several lines
    of code that reuse an existing largish predicate with the single line
    of code from that predicate that we actually need.

    Stop representing the statuses of pragmas using the pred_status type,
    since the item_mercury_status that all items come with is adequate
    for all our needs, and is impossible to confuse with the status
    of the pred_info they refer to.

library/exception.m:
library/require.m:
    Move termination pragmas for exported predicates and functions
    from the implementation section to the interface section. This
    avoids a warning that we now generate in such situations.

tests/term/exception_analysis_test.trans_opt_exp:
tests/term/exception_analysis_test2.trans_opt_exp:
    Expected improved termination analysis results now that we export
    termination pragmas that used to be kept private.

tests/warnings/foreign_term_invalid.{m,exp}:
    Avoid warnings about keeping decl pragmas about exported predicates
    private by moving them into the interface.

    Fix the formatting of the top-of-module comment.

    Expect updated line numbers.

tests/warnings/pragma_term_conflict.{m,exp}:
    Don't avoid a warning about keeping decl pragmas about exported predicates
    private. Instead, document it as an additional purpose of this test.

    Expect both the extra warning and updated line numbers.

tests/invalid/pragma_export.{m,err_exp}:
    A new test case for testing the error message for inappropriately
    exported pragmas.

tests/invalid/Mmakefile:
    Enable the new test case.
2022-09-24 19:12:18 +10:00

281 lines
8.4 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1993-1999, 2003, 2005-2006, 2010-2011 The University of Melbourne.
% Copyright (C) 2014-2016, 2018, 2021 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
% File: require.m.
% Main author: fjh.
% Stability: medium to high.
%
% This module provides features similar to <assert.h> in C.
%
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- module require.
:- interface.
% error(Message):
%
% Throw a `software_error(Message)' exception.
% This will normally cause execution to abort with an error message.
%
:- pred error(string::in) is erroneous.
% func_error(Message):
%
% An expression that results in a `software_error(Message)'
% exception being thrown.
%
:- func func_error(string) = _ is erroneous.
% error(Pred, Message):
% func_error(Pred, Message):
%
% Equivalent to invoking error or func_error on the string
% Pred ++ ": " ++ Message.
%
:- pred error(string::in, string::in) is erroneous.
:- func func_error(string, string) = _ is erroneous.
% We declare error to be terminating so that all of the standard library
% will treat it as terminating.
:- pragma terminates(pred(error/1)).
:- pragma terminates(pred(error/2)).
:- pragma terminates(func(func_error/1)).
:- pragma terminates(func(func_error/2)).
%---------------------------------------------------------------------------%
% sorry(Module, What):
%
% Call error/1 with the string
% "Module: Sorry, not implemented: What".
%
% Use this for features that should be implemented (or at least could be
% implemented).
%
:- func sorry(string, string) = _ is erroneous.
:- pred sorry(string::in, string::in) is erroneous.
% sorry(Module, Proc, What):
%
% Call error/1 with the string
% "Module: Proc: Sorry, not implemented: What".
%
% Use this for features that should be implemented,
% or at least could be implemented.
%
:- func sorry(string, string, string) = _ is erroneous.
:- pred sorry(string::in, string::in, string::in) is erroneous.
% unexpected(Module, Message):
%
% Call error/1 with the string
% "Module: Unexpected: What".
%
% Use this to handle cases which are not expected to arise (i.e. bugs).
%
:- func unexpected(string, string) = _ is erroneous.
:- pred unexpected(string::in, string::in) is erroneous.
% unexpected(Module, Proc, Message):
%
% Call error/1 with the string
% "Module: Proc: Unexpected: What".
%
% Use this to handle cases which are not expected to arise (i.e. bugs).
%
:- func unexpected(string, string, string) = _ is erroneous.
:- pred unexpected(string::in, string::in, string::in) is erroneous.
%---------------------------------------------------------------------------%
% require(Goal, Message):
%
% Call goal, and call error(Message) if Goal fails.
% This is not as useful as you might imagine, since it requires
% that the goal not produce any output variables. In most circumstances,
% you should use an explicit if-then-else with a call to error/1,
% or one of its wrappers, in the "else".
%
:- pred require((pred)::((pred) is semidet), string::in) is det.
% expect(Goal, Module, Message):
%
% Call Goal, and call unexpected(Module, Message) if Goal fails.
%
:- pred expect((pred)::((pred) is semidet), string::in, string::in) is det.
% expect(Goal, Module, Proc, Message):
%
% Call Goal, and call unexpected(Module, Proc, Message) if Goal fails.
%
:- pred expect((pred)::((pred) is semidet), string::in, string::in,
string::in) is det.
% expect_not(Goal, Module, Message):
%
% Call Goal, and call unexpected(Module, Message) if Goal succeeds.
%
:- pred expect_not((pred)::((pred) is semidet), string::in, string::in) is det.
% expect_not(Goal, Module, Proc, Message):
%
% Call Goal, and call unexpected(Module, Proc, Message) if Goal succeeds.
%
:- pred expect_not((pred)::((pred) is semidet), string::in, string::in,
string::in) is det.
%---------------------------------------------------------------------------%
% report_lookup_error(Message, Key):
%
% Call error/1 with an error message that is appropriate for
% the failure of a lookup operation involving the specified Key.
% The error message will include Message and information about Key.
%
:- pred report_lookup_error(string::in, K::in) is erroneous.
% report_lookup_error(Message, Key, Value):
%
% Call error/1 with an error message that is appropriate for
% the failure of a lookup operation involving the specified Key and Value.
% The error message will include Message and information about Key
% and Value.
%
:- pred report_lookup_error(string::in, K::in, V::unused) is erroneous.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
% :- import_module bool.
:- import_module exception.
:- import_module list.
:- import_module string.
:- import_module type_desc.
%---------------------------------------------------------------------------%
% Hopefully error won't be called often (!), so no point inlining it.
:- pragma no_inline(pred(error/1)).
:- pragma no_inline(pred(error/2)).
:- pragma no_inline(func(func_error/1)).
:- pragma no_inline(func(func_error/2)).
error(Message) :-
throw(software_error(Message)).
func_error(Message) = _ :-
error(Message).
error(Pred, Message) :-
error(Pred ++ ": " ++ Message).
func_error(Pred, Message) = _ :-
error(Pred, Message).
%---------------------------------------------------------------------------%
sorry(Module, What) = _ :-
sorry(Module, What).
sorry(Module, What) :-
string.format("%s: Sorry, not implemented: %s",
[s(Module), s(What)], ErrorMessage),
error(ErrorMessage).
sorry(Module, Proc, What) = _ :-
sorry(Module, Proc, What).
sorry(Module, Proc, What) :-
string.format("%s: %s: Sorry, not implemented: %s",
[s(Module), s(Proc), s(What)], ErrorMessage),
error(ErrorMessage).
unexpected(Module, What) = _ :-
unexpected(Module, What).
unexpected(Module, What) :-
string.format("%s: Unexpected: %s", [s(Module), s(What)], ErrorMessage),
error(ErrorMessage).
unexpected(Module, Proc, What) = _ :-
unexpected(Module, Proc, What).
unexpected(Module, Proc, What) :-
string.format("%s: %s: Unexpected: %s", [s(Module), s(Proc), s(What)],
ErrorMessage),
error(ErrorMessage).
%---------------------------------------------------------------------------%
require(Goal, Message) :-
( if call(Goal) then
true
else
error(Message)
).
expect(Goal, Module, Message) :-
( if Goal then
true
else
unexpected(Module, Message)
).
expect(Goal, Module, Proc, Message) :-
( if Goal then
true
else
unexpected(Module, Proc, Message)
).
expect_not(Goal, Module, Message) :-
( if Goal then
unexpected(Module, Message)
else
true
).
expect_not(Goal, Module, Proc, Message) :-
( if Goal then
unexpected(Module, Proc, Message)
else
true
).
%---------------------------------------------------------------------------%
report_lookup_error(Msg, K) :-
KeyType = type_name(type_of(K)),
string.append_list(
[Msg,
"\n\tKey Type: ",
KeyType,
"\n\tKey Value: ",
string(K)
],
ErrorString),
error(ErrorString).
report_lookup_error(Msg, K, V) :-
KeyType = type_name(type_of(K)),
ValueType = type_name(type_of(V)),
string.append_list(
[Msg,
"\n\tKey Type: ",
KeyType,
"\n\tKey Value: ",
string(K),
"\n\tValue Type: ",
ValueType
],
ErrorString),
error(ErrorString).
%---------------------------------------------------------------------------%
:- end_module require.
%---------------------------------------------------------------------------%