mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-18 15:26:31 +00:00
Estimated hours taken: 8 Branches: main Make error messages for require_complete_switch scopes report the missing functors. Knowing which functors are missing requires knowing not only the set of functors in the switched-on variable's type, but also which of these functors have been eliminated by earlier tests, which requires having the instmap at the point of entry to the switch. Simplification, which initially detected unmet require_complete_switch requirements, does not have the instmap, and threading the instmap through it would make it significantly less efficient. So instead we now detect any problems with require_complete_switch scopes (and require_detism scopes, which are similar) during determinism checking. compiler/det_report.m: Factor out the code for finding the missing functors in conventional determinism errors, to allow it to be used for this new purpose. Check whether the requirements of require_complete_switch and require_detism scopes are met IF the predicate has any such scopes. compiler/det_analysis.m: compiler/det_util.m: Record whether the predicate has any such scopes. compiler/hlds_pred.m: Add a predicate marker that allows this recording. compiler/simplify.m: Delete the code that checks the require_complete_switch and require_detism scopes. Keep the code that deletes those scopes. (We have to do that here because determinism error reporting never updates the goal). compiler/prog_out.m: Delete an unused predicate. compiler/*.m: Remove unnecesary imports as flagged by --warn-unused-imports.
410 lines
16 KiB
Mathematica
410 lines
16 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-2009, 2011 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: read_modules.m.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.read_modules.
|
|
:- interface.
|
|
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.timestamp.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module parse_tree.error_util.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.module_imports.
|
|
:- import_module parse_tree.prog_item.
|
|
:- import_module parse_tree.prog_io.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module pair.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% recompilation_check.m records each file read to avoid reading it again.
|
|
% The string is the suffix of the file name.
|
|
%
|
|
:- type have_read_module_map ==
|
|
map(pair(module_name, string), have_read_module).
|
|
|
|
:- type have_read_module
|
|
---> have_read_module(
|
|
module_timestamp,
|
|
list(item),
|
|
list(error_spec),
|
|
module_error,
|
|
file_name
|
|
).
|
|
|
|
% read_module(Globals, ModuleName, Extension, Descr, Search,
|
|
% ReturnTimestamp, Items, Specs, Error, SourceFileName, MaybeTimestamp):
|
|
%
|
|
% Given a module name and a file extension (e.g. `.m', `.int', or `int2'),
|
|
% read in the list of items in that file.
|
|
%
|
|
% If Extension is ".m", and ModuleName is a nested module, then try
|
|
% searching for different filenames: for modules such as `foo.bar.baz.m'
|
|
% search first for `foo.bar.baz.m', then `bar.baz.m', then `baz.m'.
|
|
% If Search is do_search, search all directories given by the option
|
|
% search_directories for the module.
|
|
% If ReturnTimestamp is do_return_timestamp, attempt to return the
|
|
% modification time of the file in MaybeTimestamp.
|
|
% If the actual module name (as determined by the `:- module' declaration)
|
|
% does not match the specified module name, then report an error message.
|
|
% Return the actual source file name found (excluding the directory part).
|
|
%
|
|
% N.B. This reads a module given the module name. If you want to read
|
|
% a module given the file name, use `read_module_from_file'.
|
|
%
|
|
:- pred read_module(globals::in, module_name::in, string::in, string::in,
|
|
maybe_search::in, maybe_return_timestamp::in, list(item)::out,
|
|
list(error_spec)::out, module_error::out, file_name::out,
|
|
maybe(timestamp)::out, io::di, io::uo) is det.
|
|
|
|
% read_module_if_changed(Globals, ModuleName, Extension, Descr, Search,
|
|
% OldTimestamp, Items, Specs, Error, SourceFileName, MaybeTimestamp):
|
|
%
|
|
% If the timestamp of the file specified by the given module name and
|
|
% file extension is newer than OldTimestamp, read the file, returning
|
|
% the new timestamp.
|
|
%
|
|
% If the file was read, MaybeTimestamp will contain the new timestamp.
|
|
% If the timestamp was unchanged, MaybeTimestamp will be
|
|
% `yes(OldTimestamp)'. If the file could not be read, MaybeTimestamp
|
|
% will be `no'.
|
|
%
|
|
:- pred read_module_if_changed(globals::in, module_name::in,
|
|
string::in, string::in, maybe_search::in, timestamp::in, list(item)::out,
|
|
list(error_spec)::out, module_error::out, file_name::out,
|
|
maybe(timestamp)::out, io::di, io::uo) is det.
|
|
|
|
% Similar to read_module, but doesn't return error messages.
|
|
%
|
|
:- pred read_module_ignore_errors(globals::in, module_name::in,
|
|
string::in, string::in, maybe_search::in, maybe_return_timestamp::in,
|
|
list(item)::out, module_error::out, file_name::out, maybe(timestamp)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% read_module_from_file(SourceFileName, Extension, Descr, Search,
|
|
% ReturnTimestamp, Items, Specs, Error, ModuleName, MaybeTimestamp):
|
|
%
|
|
% Given a file name and a file extension (e.g. `.m', `.int', or `int2'),
|
|
% read in the list of items in that file.
|
|
% If Search is do_search, search all directories given by the option
|
|
% search_directories for the module.
|
|
% If ReturnTimestamp is do_return_timestamp, attempt to return the
|
|
% modification time of the file in MaybeTimestamp. Return the module name
|
|
% (as determined by the `:- module' declaration, if any).
|
|
%
|
|
% N.B. This reads a module given the file name. If you want to read a
|
|
% module given the module name, use `read_mod'.
|
|
%
|
|
:- pred read_module_from_file(globals::in, file_name::in, string::in,
|
|
string::in, maybe_search::in, maybe_return_timestamp::in, list(item)::out,
|
|
list(error_spec)::out, module_error::out, module_name::out,
|
|
maybe(timestamp)::out, io::di, io::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred maybe_read_module(globals::in, have_read_module_map::in,
|
|
module_name::in, string::in, string::in, maybe_search::in,
|
|
maybe_return_timestamp::in, list(item)::out, list(error_spec)::out,
|
|
module_error::out, file_name::out, maybe(timestamp)::out, io::di, io::uo)
|
|
is det.
|
|
|
|
% find_read_module(HaveReadModuleMap, ModuleName, Suffix,
|
|
% ReturnTimestamp, Items, Specs, Error, FileName, MaybeTimestamp)
|
|
%
|
|
% Check whether a file was read during recompilation checking.
|
|
%
|
|
:- pred find_read_module(have_read_module_map::in, module_name::in,
|
|
string::in, maybe_return_timestamp::in, list(item)::out,
|
|
list(error_spec)::out, module_error::out,
|
|
file_name::out, maybe(timestamp)::out) is semidet.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.error_util.
|
|
|
|
:- import_module bool.
|
|
:- import_module dir.
|
|
:- import_module string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type maybe_ignore_errors
|
|
---> ignore_errors
|
|
; do_not_ignore_errors.
|
|
|
|
read_module(Globals, ModuleName, Extension, Descr, Search, ReturnTimestamp,
|
|
Items, Specs, Error, FileName, MaybeTimestamp, !IO) :-
|
|
do_read_module(Globals, do_not_ignore_errors, ModuleName, Extension,
|
|
Descr, Search, no, ReturnTimestamp, Items, Specs, Error,
|
|
FileName, MaybeTimestamp, !IO).
|
|
|
|
read_module_if_changed(Globals, ModuleName, Extension, Descr, Search,
|
|
OldTimestamp, Items, Specs, Error, FileName, MaybeTimestamp, !IO) :-
|
|
do_read_module(Globals, do_not_ignore_errors, ModuleName, Extension,
|
|
Descr, Search, yes(OldTimestamp), do_return_timestamp, Items, Specs,
|
|
Error, FileName, MaybeTimestamp, !IO).
|
|
|
|
read_module_ignore_errors(Globals, ModuleName, Extension, Descr, Search,
|
|
ReturnTimestamp, Items, Error, FileName, MaybeTimestamp, !IO) :-
|
|
do_read_module(Globals, ignore_errors, ModuleName, Extension,
|
|
Descr, Search, no, ReturnTimestamp, Items, _Specs, Error,
|
|
FileName, MaybeTimestamp, !IO).
|
|
|
|
:- pred do_read_module(globals::in, maybe_ignore_errors::in, module_name::in,
|
|
string::in, string::in, maybe_search::in, maybe(timestamp)::in,
|
|
maybe_return_timestamp::in, list(item)::out, list(error_spec)::out,
|
|
module_error::out, file_name::out, maybe(timestamp)::out, io::di, io::uo)
|
|
is det.
|
|
|
|
do_read_module(Globals, IgnoreErrors, ModuleName, Extension, Descr, Search,
|
|
MaybeOldTimestamp, ReturnTimestamp, Items, Specs, Error, FileName,
|
|
MaybeTimestamp, !IO) :-
|
|
(
|
|
Search = do_search,
|
|
module_name_to_search_file_name(Globals, ModuleName, Extension,
|
|
FileName0, !IO)
|
|
;
|
|
Search = do_not_search,
|
|
module_name_to_file_name(Globals, ModuleName, Extension,
|
|
do_not_create_dirs, FileName0, !IO)
|
|
),
|
|
globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
|
|
Msg = "% " ++ Descr ++ " `" ++ FileName0 ++ "'... ",
|
|
maybe_write_string(VeryVerbose, Msg, !IO),
|
|
maybe_flush_output(VeryVerbose, !IO),
|
|
|
|
globals.lookup_accumulating_option(Globals, search_directories,
|
|
InterfaceSearchDirs),
|
|
(
|
|
Search = do_search,
|
|
SearchDirs = InterfaceSearchDirs
|
|
;
|
|
Search = do_not_search,
|
|
SearchDirs = [dir.this_directory]
|
|
),
|
|
( Extension = ".m" ->
|
|
% For `.m' files we need to deal with the case where the module name
|
|
% does not match the file name, or where a partial match occurs
|
|
% in the current directory but the full match occurs in a
|
|
% search directory.
|
|
|
|
OpenFile = search_for_module_source(Globals, SearchDirs,
|
|
InterfaceSearchDirs, ModuleName)
|
|
;
|
|
OpenFile = search_for_file(open_file, SearchDirs, FileName0)
|
|
),
|
|
(
|
|
MaybeOldTimestamp = yes(OldTimestamp),
|
|
actually_read_module_if_changed(Globals, OpenFile, ModuleName,
|
|
OldTimestamp, MaybeFileName, ActualModuleName,
|
|
Items, ModuleSpecs, Error, MaybeTimestamp0, !IO)
|
|
;
|
|
MaybeOldTimestamp = no,
|
|
actually_read_module(Globals, OpenFile, ModuleName, ReturnTimestamp,
|
|
MaybeFileName, ActualModuleName, Items, ModuleSpecs, Error,
|
|
MaybeTimestamp0, !IO)
|
|
),
|
|
|
|
(
|
|
MaybeFileName = yes(FileName)
|
|
;
|
|
MaybeFileName = no,
|
|
FileName = FileName0
|
|
),
|
|
check_module_has_expected_name(FileName, ModuleName, ActualModuleName,
|
|
NameSpecs),
|
|
|
|
check_timestamp(Globals, FileName0, MaybeTimestamp0, MaybeTimestamp, !IO),
|
|
(
|
|
IgnoreErrors = ignore_errors,
|
|
Specs = NameSpecs, % Do not include ModuleSpecs.
|
|
(
|
|
Error = fatal_module_errors,
|
|
Items = []
|
|
->
|
|
maybe_write_string(VeryVerbose, "not found.\n", !IO)
|
|
;
|
|
maybe_write_string(VeryVerbose, "done.\n", !IO)
|
|
)
|
|
;
|
|
IgnoreErrors = do_not_ignore_errors,
|
|
ModuleNameSpecs = NameSpecs ++ ModuleSpecs,
|
|
(
|
|
Error = fatal_module_errors,
|
|
maybe_write_string(VeryVerbose, "fatal error(s).\n", !IO),
|
|
maybe_write_out_errors_no_module(VeryVerbose, Globals,
|
|
ModuleNameSpecs, Specs, !IO),
|
|
io.set_exit_status(1, !IO)
|
|
;
|
|
Error = some_module_errors,
|
|
maybe_write_string(VeryVerbose, "parse error(s).\n", !IO),
|
|
maybe_write_out_errors_no_module(VeryVerbose, Globals,
|
|
ModuleNameSpecs, Specs, !IO),
|
|
io.set_exit_status(1, !IO)
|
|
;
|
|
Error = no_module_errors,
|
|
maybe_write_string(VeryVerbose, "successful parse.\n", !IO),
|
|
Specs = ModuleNameSpecs
|
|
)
|
|
).
|
|
|
|
read_module_from_file(Globals, FileName, Extension, Descr, Search,
|
|
ReturnTimestamp, Items, Specs, Error, ModuleName, MaybeTimestamp,
|
|
!IO) :-
|
|
globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
|
|
maybe_write_string(VeryVerbose, "% ", !IO),
|
|
maybe_write_string(VeryVerbose, Descr, !IO),
|
|
maybe_write_string(VeryVerbose, " `", !IO),
|
|
maybe_write_string(VeryVerbose, FileName, !IO),
|
|
maybe_write_string(VeryVerbose, "'... ", !IO),
|
|
maybe_flush_output(VeryVerbose, !IO),
|
|
string.append(FileName, Extension, FullFileName),
|
|
( dir.basename(FileName, BaseFileNamePrime) ->
|
|
BaseFileName = BaseFileNamePrime
|
|
;
|
|
BaseFileName = ""
|
|
),
|
|
file_name_to_module_name(BaseFileName, DefaultModuleName),
|
|
(
|
|
Search = do_search,
|
|
globals.lookup_accumulating_option(Globals, search_directories,
|
|
SearchDirs)
|
|
;
|
|
Search = do_not_search,
|
|
SearchDirs = [dir.this_directory]
|
|
),
|
|
OpenFile = search_for_file(open_file, SearchDirs, FullFileName),
|
|
actually_read_module(Globals, OpenFile, DefaultModuleName, ReturnTimestamp,
|
|
_, ModuleName, Items, Specs0, Error, MaybeTimestamp0, !IO),
|
|
check_timestamp(Globals, FullFileName, MaybeTimestamp0, MaybeTimestamp,
|
|
!IO),
|
|
(
|
|
Error = fatal_module_errors,
|
|
maybe_write_string(VeryVerbose, "fatal error(s).\n", !IO),
|
|
maybe_write_out_errors_no_module(VeryVerbose, Globals, Specs0, Specs,
|
|
!IO),
|
|
io.set_exit_status(1, !IO)
|
|
;
|
|
Error = some_module_errors,
|
|
maybe_write_string(VeryVerbose, "parse error(s).\n", !IO),
|
|
maybe_write_out_errors_no_module(VeryVerbose, Globals, Specs0, Specs,
|
|
!IO),
|
|
io.set_exit_status(1, !IO)
|
|
;
|
|
Error = no_module_errors,
|
|
maybe_write_string(VeryVerbose, "successful parse.\n", !IO),
|
|
Specs = Specs0
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
maybe_read_module(Globals, HaveReadModuleMap, ModuleName, Extension, Descr,
|
|
Search, ReturnTimestamp, Items, Specs, Error, FileName, MaybeTimestamp,
|
|
!IO) :-
|
|
(
|
|
find_read_module(HaveReadModuleMap, ModuleName, Extension,
|
|
ReturnTimestamp, ItemsPrime, SpecsPrime, ErrorPrime,
|
|
FileNamePrime, MaybeTimestampPrime)
|
|
->
|
|
Error = ErrorPrime,
|
|
Items = ItemsPrime,
|
|
Specs = SpecsPrime,
|
|
MaybeTimestamp = MaybeTimestampPrime,
|
|
FileName = FileNamePrime
|
|
;
|
|
read_module(Globals, ModuleName, Extension, Descr, Search,
|
|
ReturnTimestamp, Items, Specs, Error, FileName, MaybeTimestamp,
|
|
!IO)
|
|
).
|
|
|
|
find_read_module(HaveReadModuleMap, ModuleName, Suffix, ReturnTimestamp,
|
|
Items, Specs, Error, FileName, MaybeTimestamp) :-
|
|
map.search(HaveReadModuleMap, ModuleName - Suffix, HaveReadModule),
|
|
HaveReadModule = have_read_module(ModuleTimestamp, Items, Specs, Error,
|
|
FileName),
|
|
(
|
|
ReturnTimestamp = do_return_timestamp,
|
|
ModuleTimestamp = module_timestamp(_, Timestamp, _),
|
|
MaybeTimestamp = yes(Timestamp)
|
|
;
|
|
ReturnTimestamp = do_not_return_timestamp,
|
|
MaybeTimestamp = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred check_timestamp(globals::in, file_name::in,
|
|
maybe(io.res(timestamp))::in, maybe(timestamp)::out,
|
|
io::di, io::uo) is det.
|
|
|
|
check_timestamp(Globals, FileName, MaybeTimestamp0, MaybeTimestamp, !IO) :-
|
|
(
|
|
MaybeTimestamp0 = yes(ok(Timestamp)),
|
|
MaybeTimestamp = yes(Timestamp)
|
|
;
|
|
MaybeTimestamp0 = yes(error(IOError)),
|
|
MaybeTimestamp = no,
|
|
globals.lookup_bool_option(Globals, smart_recompilation,
|
|
SmartRecompilation),
|
|
% Should we print the warning if smart recompilation has already been
|
|
% disabled by an earlier error? At the moment, we do.
|
|
(
|
|
SmartRecompilation = yes,
|
|
report_modification_time_warning(Globals, FileName, IOError, !IO)
|
|
;
|
|
SmartRecompilation = no
|
|
)
|
|
;
|
|
MaybeTimestamp0 = no,
|
|
MaybeTimestamp = no
|
|
).
|
|
|
|
:- pred report_modification_time_warning(globals::in, file_name::in,
|
|
io.error::in, io::di, io::uo) is det.
|
|
|
|
report_modification_time_warning(Globals, SourceFileName, Error, !IO) :-
|
|
io_set_disable_smart_recompilation(yes, !IO),
|
|
io_set_disable_generate_item_version_numbers(yes, !IO),
|
|
globals.lookup_bool_option(Globals, warn_smart_recompilation, Warn),
|
|
(
|
|
Warn = yes,
|
|
io.write_string("Warning: cannot find modification time for ", !IO),
|
|
io.write_string(SourceFileName, !IO),
|
|
io.write_string(":\n", !IO),
|
|
io.error_message(Error, Msg),
|
|
io.write_string(" ", !IO),
|
|
io.write_string(Msg, !IO),
|
|
io.write_string(".\n", !IO),
|
|
io.write_string(" Smart recompilation will not work.\n", !IO),
|
|
globals.lookup_bool_option(Globals, halt_at_warn, HaltAtWarn),
|
|
(
|
|
HaltAtWarn = yes,
|
|
io.set_exit_status(1, !IO)
|
|
;
|
|
HaltAtWarn = no
|
|
)
|
|
;
|
|
Warn = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|