mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
Fix bugs in the handling of nested sub-modules with --smart-recompilation.
Estimated hours taken: 1 Branches: main Fix bugs in the handling of nested sub-modules with --smart-recompilation. compiler/recompilation_check.m: If an error occurs before the nested sub-modules of the top-level module are known, recompile all of the nested sub-modules. If there is a syntax error in a `.used' file, recompile all sub-modules. This makes the above change simpler, and is probably a good idea anyway -- all outputs from a compilation which produces output files containing syntax errors are suspect. compiler/mercury_compile.m: When working out the list of sub-modules of the main module in a source file, use all the sub-modules, not just the ones that are being recompiled. tests/recompilation/Mmakefile: tests/recompilation/TESTS: tests/recompilation/nested_module_2_r*: Test case.
This commit is contained in:
@@ -721,11 +721,11 @@ process_module_2(FileOrModule, MaybeModulesToRecompile, ReadModules0,
|
||||
list__member(SubModule,
|
||||
ModulesToRecompile)
|
||||
),
|
||||
SubModuleList0, SubModuleList)
|
||||
SubModuleList0, SubModuleListToCompile)
|
||||
;
|
||||
SubModuleList = SubModuleList0
|
||||
SubModuleListToCompile = SubModuleList0
|
||||
},
|
||||
{ assoc_list__keys(SubModuleList, NestedSubModules0) },
|
||||
{ assoc_list__keys(SubModuleList0, NestedSubModules0) },
|
||||
{ list__delete_all(NestedSubModules0,
|
||||
ModuleName, NestedSubModules) },
|
||||
|
||||
@@ -751,7 +751,7 @@ process_module_2(FileOrModule, MaybeModulesToRecompile, ReadModules0,
|
||||
compile_all_submodules(FileName,
|
||||
ModuleName - NestedSubModules,
|
||||
MaybeTimestamp, ReadModules,
|
||||
FindTimestampFiles, SubModuleList,
|
||||
FindTimestampFiles, SubModuleListToCompile,
|
||||
ModulesToLink),
|
||||
|
||||
globals__io_set_option(trace_stack_layout, bool(TSL)),
|
||||
@@ -760,7 +760,7 @@ process_module_2(FileOrModule, MaybeModulesToRecompile, ReadModules0,
|
||||
compile_all_submodules(FileName,
|
||||
ModuleName - NestedSubModules,
|
||||
MaybeTimestamp, ReadModules,
|
||||
FindTimestampFiles, SubModuleList,
|
||||
FindTimestampFiles, SubModuleListToCompile,
|
||||
ModulesToLink)
|
||||
)
|
||||
).
|
||||
|
||||
@@ -131,7 +131,7 @@ recompilation_check__should_recompile_2(IsSubModule, FindTargetFiles,
|
||||
io__set_input_stream(OldInputStream, VersionStream),
|
||||
io__close_input(VersionStream),
|
||||
|
||||
( { (all) = Info1 ^ modules_to_recompile } ->
|
||||
( { (all) = Info4 ^ modules_to_recompile } ->
|
||||
{ Info = Info4 }
|
||||
;
|
||||
{ Info5 = Info4 ^ is_inline_sub_module := yes },
|
||||
@@ -158,6 +158,15 @@ recompilation_check__should_recompile_2(IsSubModule, FindTargetFiles,
|
||||
|
||||
recompilation_check__should_recompile_3(IsSubModule, FindTargetFiles,
|
||||
Info0, Info) -->
|
||||
|
||||
%
|
||||
% WARNING: any exceptions thrown before the sub_modules
|
||||
% field is set in the recompilation_check_info must set
|
||||
% the modules_to_recompile field to `all', or else
|
||||
% the nested sub-modules will not be checked and necessary
|
||||
% recompilations may be missed.
|
||||
%
|
||||
|
||||
%
|
||||
% Check that the format of the usage file is the current format.
|
||||
%
|
||||
@@ -179,11 +188,11 @@ recompilation_check__should_recompile_3(IsSubModule, FindTargetFiles,
|
||||
[]
|
||||
;
|
||||
io__input_stream_name(UsageFileName),
|
||||
{ throw(recompile_exception(
|
||||
{ throw_syntax_error(
|
||||
file_error(UsageFileName,
|
||||
"invalid usage file version number in file `"
|
||||
++ UsageFileName ++ "'."),
|
||||
Info0)) }
|
||||
Info0) }
|
||||
),
|
||||
|
||||
%
|
||||
@@ -213,45 +222,26 @@ recompilation_check__should_recompile_3(IsSubModule, FindTargetFiles,
|
||||
->
|
||||
record_read_file(ModuleName,
|
||||
ModuleTimestamp ^ timestamp := NewTimestamp,
|
||||
Items, Error, FileName, Info0, ErrorInfo),
|
||||
Items, Error, FileName, Info0, RecompileInfo0),
|
||||
RecompileInfo =
|
||||
RecompileInfo0 ^ modules_to_recompile := (all),
|
||||
throw(recompile_exception(module_changed(FileName),
|
||||
ErrorInfo))
|
||||
RecompileInfo))
|
||||
;
|
||||
( Error \= no_module_errors
|
||||
; MaybeNewTimestamp = no
|
||||
)
|
||||
->
|
||||
throw(recompile_exception(
|
||||
throw_syntax_error(
|
||||
file_error(FileName,
|
||||
"error reading file `"
|
||||
++ FileName ++ "'."),
|
||||
Info0))
|
||||
Info0)
|
||||
;
|
||||
true
|
||||
}
|
||||
),
|
||||
|
||||
%
|
||||
% Check whether the output files are present and up-to-date.
|
||||
%
|
||||
FindTargetFiles(Info0 ^ module_name, TargetFiles),
|
||||
list__foldl(
|
||||
(pred(TargetFile::in, di, uo) is det -->
|
||||
io__file_modification_time(TargetFile, TargetModTimeResult),
|
||||
(
|
||||
{ TargetModTimeResult = ok(TargetModTime) },
|
||||
{ compare(TargetModTimeCompare,
|
||||
time_t_to_timestamp(TargetModTime),
|
||||
RecordedTimestamp) },
|
||||
{ TargetModTimeCompare = (>) }
|
||||
->
|
||||
[]
|
||||
;
|
||||
{ Reason1 = output_file_not_up_to_date(TargetFile) },
|
||||
{ throw(recompile_exception(Reason1, Info0)) }
|
||||
)
|
||||
), TargetFiles),
|
||||
|
||||
%
|
||||
% Find out whether this module has any inline sub-modules.
|
||||
%
|
||||
@@ -268,11 +258,32 @@ recompilation_check__should_recompile_3(IsSubModule, FindTargetFiles,
|
||||
->
|
||||
Info1 = Info0 ^ sub_modules := SubModules
|
||||
;
|
||||
Reason2 = syntax_error(get_term_context(SubModulesTerm),
|
||||
Reason1 = syntax_error(get_term_context(SubModulesTerm),
|
||||
"error in sub_modules term"),
|
||||
throw(recompile_exception(Reason2, Info0))
|
||||
throw_syntax_error(Reason1, Info0)
|
||||
},
|
||||
|
||||
%
|
||||
% Check whether the output files are present and up-to-date.
|
||||
%
|
||||
FindTargetFiles(Info1 ^ module_name, TargetFiles),
|
||||
list__foldl(
|
||||
(pred(TargetFile::in, di, uo) is det -->
|
||||
io__file_modification_time(TargetFile, TargetModTimeResult),
|
||||
(
|
||||
{ TargetModTimeResult = ok(TargetModTime) },
|
||||
{ compare(TargetModTimeCompare,
|
||||
time_t_to_timestamp(TargetModTime),
|
||||
RecordedTimestamp) },
|
||||
{ TargetModTimeCompare = (>) }
|
||||
->
|
||||
[]
|
||||
;
|
||||
{ Reason2 = output_file_not_up_to_date(TargetFile) },
|
||||
{ throw(recompile_exception(Reason2, Info1)) }
|
||||
)
|
||||
), TargetFiles),
|
||||
|
||||
%
|
||||
% Read in the used items, used for checking for
|
||||
% ambiguities with new items.
|
||||
@@ -299,7 +310,7 @@ recompilation_check__should_recompile_3(IsSubModule, FindTargetFiles,
|
||||
;
|
||||
Reason3 = syntax_error(get_term_context(UsedClassesTerm),
|
||||
"error in used_typeclasses term"),
|
||||
throw(recompile_exception(Reason3, Info2))
|
||||
throw_syntax_error(Reason3, Info2)
|
||||
},
|
||||
check_imported_modules(Info3, Info).
|
||||
|
||||
@@ -332,7 +343,7 @@ parse_module_timestamp(Info, Term, ModuleName, ModuleTimestamp) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in module timestamp"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
%-----------------------------------------------------------------------------%
|
||||
@@ -348,7 +359,7 @@ parse_used_items(Info, Term, UsedItems) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in used items"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_used_item_set(recompilation_check_info::in, term::in,
|
||||
@@ -378,12 +389,12 @@ parse_used_item_set(Info, Term, UsedItems0, UsedItems) :-
|
||||
string__append(
|
||||
"error in used items: unknown item type :",
|
||||
ItemTypeStr)),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
)
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in used items"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_simple_item(recompilation_check_info::in, term::in,
|
||||
@@ -403,7 +414,7 @@ parse_simple_item(Info, Term, Set0, Set) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in simple items"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_simple_item_match(recompilation_check_info::in, term::in,
|
||||
@@ -427,7 +438,7 @@ parse_simple_item_match(Info, Term, Items0, Items) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in simple item match"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_pred_or_func_item(recompilation_check_info::in,
|
||||
@@ -448,7 +459,7 @@ parse_pred_or_func_item(Info, Term, Set0, Set) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in pred or func match"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_pred_or_func_item_match(recompilation_check_info::in, term::in,
|
||||
@@ -479,7 +490,7 @@ parse_pred_or_func_item_match(Info, Term, Items0, Items) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in pred or func match"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_functor_item(recompilation_check_info::in, term::in,
|
||||
@@ -498,7 +509,7 @@ parse_functor_item(Info, Term, Set0, Set) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in functor matches"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_functor_arity_matches(recompilation_check_info::in, term::in,
|
||||
@@ -517,7 +528,7 @@ parse_functor_arity_matches(Info, Term, Arity - MatchMap) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in functor match"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_functor_matches(recompilation_check_info::in, term::in,
|
||||
@@ -537,7 +548,7 @@ parse_functor_matches(Info, Term, Map0, Map) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in functor match"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
:- pred parse_resolved_functor(recompilation_check_info::in, term::in,
|
||||
@@ -571,7 +582,7 @@ parse_resolved_functor(Info, Term, Ctor) :-
|
||||
;
|
||||
Reason = syntax_error(get_term_context(Term),
|
||||
"error in functor match"),
|
||||
throw(recompile_exception(Reason, Info))
|
||||
throw_syntax_error(Reason, Info)
|
||||
).
|
||||
|
||||
%-----------------------------------------------------------------------------%
|
||||
@@ -600,7 +611,7 @@ check_imported_modules(Info0, Info) -->
|
||||
io__input_stream_name(FileName),
|
||||
{ Reason = syntax_error(term__context(FileName, Line),
|
||||
Message) },
|
||||
{ throw(recompile_exception(Reason, Info0)) }
|
||||
{ throw_syntax_error(Reason, Info0) }
|
||||
;
|
||||
{ TermResult = eof },
|
||||
%
|
||||
@@ -613,7 +624,7 @@ check_imported_modules(Info0, Info) -->
|
||||
io__get_line_number(Line),
|
||||
{ Reason = syntax_error(term__context(FileName, Line),
|
||||
"unexpected end of file") },
|
||||
{ throw(recompile_exception(Reason, Info0)) }
|
||||
{ throw_syntax_error(Reason, Info0) }
|
||||
).
|
||||
|
||||
:- pred check_imported_module(term::in, recompilation_check_info::in,
|
||||
@@ -661,7 +672,8 @@ check_imported_module(Term, Info0, Info) -->
|
||||
),
|
||||
{
|
||||
MaybeNewTimestamp = yes(NewTimestamp),
|
||||
NewTimestamp \= RecordedTimestamp
|
||||
NewTimestamp \= RecordedTimestamp,
|
||||
Error = no_module_errors
|
||||
->
|
||||
( Recorded = no ->
|
||||
record_read_file(ImportedModuleName,
|
||||
@@ -687,10 +699,10 @@ check_imported_module(Term, Info0, Info) -->
|
||||
;
|
||||
Error \= no_module_errors
|
||||
->
|
||||
throw(recompile_exception(
|
||||
throw_syntax_error(
|
||||
file_error(FileName,
|
||||
"error reading file `" ++ FileName ++ "'."),
|
||||
Info0))
|
||||
Info0)
|
||||
;
|
||||
Info = Info0
|
||||
}.
|
||||
@@ -710,9 +722,8 @@ check_module_used_items(ModuleName, NeedQualifier, OldTimestamp,
|
||||
UsedItemsResult = ok(UsedVersionNumbers)
|
||||
;
|
||||
UsedItemsResult = error(Msg, ErrorTerm),
|
||||
Reason = syntax_error(get_term_context(ErrorTerm),
|
||||
Msg),
|
||||
throw(recompile_exception(Reason, Info0))
|
||||
Reason = syntax_error(get_term_context(ErrorTerm), Msg),
|
||||
throw_syntax_error(Reason, Info0)
|
||||
},
|
||||
|
||||
{ UsedVersionNumbers = version_numbers(UsedItemVersionNumbers,
|
||||
@@ -1473,7 +1484,7 @@ read_term_check_for_error_or_eof(Info, Item, Term) -->
|
||||
io__input_stream_name(FileName),
|
||||
{ Reason = syntax_error(term__context(FileName, Line),
|
||||
Message) },
|
||||
{ throw(recompile_exception(Reason, Info)) }
|
||||
{ throw_syntax_error(Reason, Info) }
|
||||
;
|
||||
{ TermResult = eof },
|
||||
io__input_stream_name(FileName),
|
||||
@@ -1482,7 +1493,7 @@ read_term_check_for_error_or_eof(Info, Item, Term) -->
|
||||
string__append_list(
|
||||
["unexpected end of file, expected ",
|
||||
Item, "."])) },
|
||||
{ throw(recompile_exception(Reason, Info)) }
|
||||
{ throw_syntax_error(Reason, Info) }
|
||||
).
|
||||
|
||||
:- func get_term_context(term) = term__context.
|
||||
@@ -1494,4 +1505,14 @@ get_term_context(Term) =
|
||||
term__context_init
|
||||
).
|
||||
|
||||
:- pred throw_syntax_error(recompile_reason::in,
|
||||
recompilation_check_info::in) is erroneous.
|
||||
|
||||
throw_syntax_error(Reason, Info) :-
|
||||
% If there were syntax errors in a `.used' file written during
|
||||
% a compilation, all outputs of that compilation are slightly
|
||||
% suspect, so it's worth entirely redoing the compilation.
|
||||
RecompileInfo = Info ^ modules_to_recompile := (all),
|
||||
throw(recompile_exception(Reason, RecompileInfo)).
|
||||
|
||||
%-----------------------------------------------------------------------------%
|
||||
|
||||
@@ -33,4 +33,7 @@ override EXTRA_MCFLAGS += --no-intermodule-optimization --smart-recompilation \
|
||||
# for which no version numbers have been computed.
|
||||
MCFLAGS-no_version_numbers_r_2 = --no-smart-recompilation
|
||||
|
||||
$(ints_subdir)nested_module_2_r_2.date: \
|
||||
$(int0s_subdir)nested_module_2_r_2.int0
|
||||
|
||||
#-----------------------------------------------------------------------------#
|
||||
|
||||
@@ -28,8 +28,8 @@ TESTS_SHOULD_SUCCEED="\
|
||||
# nested sub-module are run twice, resulting in incorrect output in
|
||||
# the `.err' file.
|
||||
NO_PARALLEL_MAKE_TESTS="\
|
||||
nested_module_r
|
||||
"
|
||||
nested_module_r \
|
||||
nested_module_2_r"
|
||||
|
||||
TESTS_SHOULD_FAIL="\
|
||||
add_type_re \
|
||||
|
||||
2
tests/recompilation/nested_module_2_r.err_exp.2
Normal file
2
tests/recompilation/nested_module_2_r.err_exp.2
Normal file
@@ -0,0 +1,2 @@
|
||||
Recompiling module `nested_module_2_r':
|
||||
file `nested_module_2_r.used' not found.
|
||||
1
tests/recompilation/nested_module_2_r.exp.1
Normal file
1
tests/recompilation/nested_module_2_r.exp.1
Normal file
@@ -0,0 +1 @@
|
||||
answer 1
|
||||
1
tests/recompilation/nested_module_2_r.exp.2
Normal file
1
tests/recompilation/nested_module_2_r.exp.2
Normal file
@@ -0,0 +1 @@
|
||||
answer 2
|
||||
14
tests/recompilation/nested_module_2_r.m.1
Normal file
14
tests/recompilation/nested_module_2_r.m.1
Normal file
@@ -0,0 +1,14 @@
|
||||
:- module nested_module_2_r.
|
||||
|
||||
:- interface.
|
||||
|
||||
:- import_module io.
|
||||
|
||||
:- pred main(io__state::di, io__state::uo) is det.
|
||||
|
||||
:- implementation.
|
||||
|
||||
:- import_module nested_module_2_r_2.
|
||||
|
||||
main -->
|
||||
main_2.
|
||||
2
tests/recompilation/nested_module_2_r_2.err_exp.2
Normal file
2
tests/recompilation/nested_module_2_r_2.err_exp.2
Normal file
@@ -0,0 +1,2 @@
|
||||
Recompiling module `nested_module_2_r_2':
|
||||
file `nested_module_2_r_2.m' has changed.
|
||||
26
tests/recompilation/nested_module_2_r_2.m.1
Normal file
26
tests/recompilation/nested_module_2_r_2.m.1
Normal file
@@ -0,0 +1,26 @@
|
||||
:- module nested_module_2_r_2.
|
||||
|
||||
:- interface.
|
||||
|
||||
:- import_module io.
|
||||
|
||||
:- pred main_2(io__state::di, io__state::uo) is det.
|
||||
|
||||
:- implementation.
|
||||
|
||||
:- import_module nested_module_2_r_2__sub_module.
|
||||
|
||||
main_2 --> main_3.
|
||||
|
||||
:- module nested_module_2_r_2__sub_module.
|
||||
|
||||
:- interface.
|
||||
|
||||
:- import_module io.
|
||||
|
||||
:- pred main_3(io__state::di, io__state::uo) is det.
|
||||
|
||||
:- implementation.
|
||||
|
||||
main_3 --> io__write_string("answer 1\n").
|
||||
|
||||
26
tests/recompilation/nested_module_2_r_2.m.2
Normal file
26
tests/recompilation/nested_module_2_r_2.m.2
Normal file
@@ -0,0 +1,26 @@
|
||||
:- module nested_module_2_r_2.
|
||||
|
||||
:- interface.
|
||||
|
||||
:- import_module io.
|
||||
|
||||
:- pred main_2(io__state::di, io__state::uo) is det.
|
||||
|
||||
:- implementation.
|
||||
|
||||
:- import_module nested_module_2_r_2__sub_module.
|
||||
|
||||
main_2 --> main_3.
|
||||
|
||||
:- module nested_module_2_r_2__sub_module.
|
||||
|
||||
:- interface.
|
||||
|
||||
:- import_module io.
|
||||
|
||||
:- pred main_3(io__state::di, io__state::uo) is det.
|
||||
|
||||
:- implementation.
|
||||
|
||||
main_3 --> io__write_string("answer 2\n").
|
||||
|
||||
Reference in New Issue
Block a user