mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 01:43:35 +00:00
compiler/decide_type_repn.m:
Previously, this module computed type_repn items to put into .int3 files
for a subset of the type constructors defined in the current module:
the direct_dummy, enum and notag types (the *simple* types),
and the du types whose representation is guaranteed to be
a word-aligned pointer when targeting C. (We care about pointers
being word-aligned only when applying the direct arg optimization.
This optimization is applicable only with the low level data
representation, which we use only when targeting C.)
This diff adds code to decide the representations of *all* the
type constructors defined in the current module.
This code is based on the existing code in du_type_layout.m,
which it is intended to eventually replace, but its job is more general,
because it decides the representation of each type not just for
one platform (the one we want to generate code), but for all possible
platforms. This is because we want to put the descriptions of type
representations into the module's .int file to serve as a single source
of truth for all modules that use the types defined in this module,
and the contents of .int files should be platform-independent.
For our purposes, there are six kinds of platforms, which are
distinguished along three axes: 64 vs 32 bit machines, spf vs non-spf
grades, and direct arg optimization enabled vs disabled. That is eight
combinations, but on 64 bit machines, a float takes up one word whether
that float is single or double precision, so two combinations aren't valid.
Some of the change to this module consists of generalizing the existing
code so that it can decide simple types not just when targeting .int3 files
but .int files as well. However, the bulk of it is code for deciding
the representations of non-simple types. The code is not lifted straight
from du_type_layout.m. There are two main kinds of changes.
First, I took the opportunity to simplify the algorithms used.
For example, while du_type_layout.m passes over each function symbol
in the most general kind of type twice: once to assign it a cons_tag,
and once to decide how to pack its arguments, the code here does both jobs
in one pass. Another example is that for historical reasons,
du_type_layout.m computed the amount of space needed for an argument
in one place for sub-word-sized arguments, and in another place
for more-than-word-sized arguments; decide_type_repn.m does it all
in one place.
Second, since we compute a representation for each type six times,
I tried to avoid obvious inefficiencies, but only if the code
remained simple. In the future, we may want to use an approach
based on the idea that in the process of computing the first
representation, we look out for any indication that the representation
may be different on any of the other five platforms, and if not,
we just reuse the first representation on the other five platforms as well.
However, that would be appropriate only *after* we have a simpler
system that has proven to work in practice.
There is a third, smaller change: when deciding whether an argument
is packable, we take into account not just equivalence type
definitions, but the definitions of notag types as well.
This takes advantage of the fact that if a notag type is abstract
exported, its representation is put into the relevant .int3 file
even though its definition isn't. (This is why du_type_layout.m
couldn't "see through" notag types: it couldn't depend on knowing
which types were notags.)
compiler/prog_item.m:
Change the types we use for type representation information.
Their previous definitions baked in the assumption that the only
distinction between platforms that mattered was the 64 vs 32 bit
distinction, which is not the case.
Use a more consistent naming scheme for the types we use
to represent type representation information.
Include the "dereferenced" types of the arguments in functors'
representations. (I use "dereferencing" here to mean expanding
equivalence types and throwing away any notag wrappers.).
We don't need it when generating C code using the low level
data representation, but we do need it to create constructors
when generating e.g. Java code that uses the high level data
representation.
compiler/parse_type_repn.m:
Rewrite most of this module due to the changes in prog_item.m.
compiler/parse_tree_out_type_repn.m:
A new module containing the code for writing out type representations.
The original code used to be in parse_tree_out.m, but it has been
mostly rewritten. Partly this is due the changes in prog_item.m,
but partly it is to provide much more structured output for humans,
since this makes debugging so much easier.
compiler/parse_tree.m:
Add the new module to the parse_tree package.
compiler/parse_tree_out.m:
Delete the code moved to parse_tree_out_type_repn.m.
compiler/parse_tree_out_info.m:
Provide a mechanism for selecting between output for machines
(the default) and output for humans.
compiler/hlds_data.m:
compiler/prog_data.m:
Move the ptag type from hlds_data.m to prog_data.m, to make it
accessible in prog_item.m.
Add some documentation in prog_data.m.
compiler/comp_unit_interface.m:
If the experiment1 option is enabled, invoke decide_type_repn.m
to decide what type_repn items to put into the .int file we are
generating. Otherwise, maintain the status quo.
compiler/write_module_interface_files.m:
Pass the globals to comp_unit_interface.m so it can look up experiment1.
compiler/equiv_type.m:
Add a predicate for expanding equivalence types for use by
decide_type_repn.m. This predicate expands just one type,
but reports any use of circular equivalence types in that type.
Improve the error message for circular equivalence types by *naming*
the type constructors involved. To make this possible, pass around
sets of such type constructors instead of just a boolean saying
*whether* we have found *some* circular equivalence type.
Replace bools used as changed/unchanged flag with a bespoke type.
Standardize some variable names.
compiler/options.m:
Add the developer-only option --pack-everything, which, if set,
tells decide_type_repn.m to turn on all the packing options
that currently work. This is to allow the testing of decide_type_repn.m
in the eventual intended mode of operation, even if the various
allow-packing-... options used by du_type_layout.m are set to "no".
compiler/disj_gen.m:
compiler/equiv_type_hlds.m:
compiler/llds_out_data.m:
compiler/lookup_util.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/mlds_to_c_data.m:
compiler/rtti.m:
compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
compiler/tag_switch.m:
Conform to the changes above (mostly the move of ptag to prog_data.m.)
compiler/parse_pragma.m:
Improve indentation.
tests/valid_make_int/test_repn.m:
tests/valid_make_int/test_repn_sub.m:
A fairly comprehensive test case of the new functionality.
test_repn_sub.m defines one ore more simple type constructors
of each possible kind, and test_repn.m uses them to define types
that use each possible kind of complex type representation.
tests/valid_make_int/Mmakefile:
tests/valid_make_int/Mercury.options:
Enable the new test case.
471 lines
20 KiB
Mathematica
471 lines
20 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2014 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: write_module_interface_files.m.
|
|
% Main author: fjh (when this code was in modules.m).
|
|
%
|
|
% This module writes the automatically generated .int3, .int2 and .int files
|
|
% (and if needed, the .int0 file) for each Mercury source module.
|
|
%
|
|
% The interface file system works as follows:
|
|
%
|
|
% 1. a .int3 file is written, which contains all the types, typeclasses, insts
|
|
% and modes defined in the interface. Equivalence types, solver types, insts
|
|
% and modes are written in full, others are written in abstract form. These
|
|
% are module qualified as far as possible given the information present in the
|
|
% current module.
|
|
%
|
|
% 2. The .int and .int2 files are created, using the .int3 files
|
|
% of imported modules to fully module qualify all items.
|
|
% The .int2 file is mostly just a fully qualified version of the .int3 file,
|
|
% however it also includes some extra information, such as functors for
|
|
% discriminated union types, which may be needed for mode analysis.
|
|
%
|
|
% 3. The .int0 file is similar to the .int file except that it also
|
|
% includes declarations (but not clauses) from the implementation section.
|
|
% It is generated only for modules that have submodules.
|
|
%
|
|
% NOTE The above is only a summary, and may be out of date. An attempt
|
|
% at an up-to-date and much more detailed description can be found in
|
|
% notes/interface_files.html.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% The datestamp on the .date3 file gives the last time
|
|
% the .int3 file was checked for consistency.
|
|
%
|
|
% The datestamp on the .date file gives the last time
|
|
% the .int and .int2 files were checked for consistency.
|
|
%
|
|
% The datestamp on the .date0 file gives the last time
|
|
% the .int0 file was checked for consistency.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.write_module_interface_files.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.timestamp.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.prog_item.
|
|
:- import_module parse_tree.read_modules.
|
|
|
|
:- import_module io.
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Output the unqualified short interface file to <module>.int3.
|
|
%
|
|
:- pred write_short_interface_file_int3(globals::in, file_name::in,
|
|
raw_compilation_unit::in, io::di, io::uo) is det.
|
|
|
|
% write_private_interface_file_int0(Globals, SourceFileName,
|
|
% SourceFileModuleName, CompUnit, MaybeTimestamp,
|
|
% !HaveReadModuleMaps, !IO):
|
|
%
|
|
% Given a source file name, the timestamp of the source file, and the
|
|
% representation of a module in that file, output the private (`.int0')
|
|
% interface file for the module. (The private interface contains all the
|
|
% declarations in the module, including those in the `implementation'
|
|
% section; it is used when compiling submodules.)
|
|
%
|
|
% XXX The comment on the predicate definition used to read:
|
|
% Read in the .int3 files that the current module depends on, and use
|
|
% these to qualify all the declarations as much as possible. Then write
|
|
% out the .int0 file.
|
|
%
|
|
:- pred write_private_interface_file_int0(globals::in, file_name::in,
|
|
module_name::in, maybe(timestamp)::in, raw_compilation_unit::in,
|
|
have_read_module_maps::in, have_read_module_maps::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% write_interface_file_int1_int2(Globals, SourceFileName,
|
|
% SourceFileModuleName, CompUnit, MaybeTimestamp,
|
|
% !HaveReadModuleMaps, !IO):
|
|
%
|
|
% Given a source file name, the timestamp of the source file, and the
|
|
% representation of a module in that file, output the long (`.int')
|
|
% and short (`.int2') interface files for the module.
|
|
%
|
|
% XXX The comment on the predicate definition used to read:
|
|
% Read in the .int3 files that the current module depends on, and use these
|
|
% to qualify all items in the interface as much as possible. Then write out
|
|
% the .int and .int2 files.
|
|
%
|
|
:- pred write_interface_file_int1_int2(globals::in, file_name::in,
|
|
module_name::in, maybe(timestamp)::in, raw_compilation_unit::in,
|
|
have_read_module_maps::in, have_read_module_maps::out,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.comp_unit_interface.
|
|
:- import_module parse_tree.convert_parse_tree.
|
|
:- import_module parse_tree.error_util.
|
|
:- import_module parse_tree.file_kind.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.grab_modules. % undesirable dependency
|
|
:- import_module parse_tree.module_cmds.
|
|
:- import_module parse_tree.module_imports.
|
|
:- import_module parse_tree.module_qual.
|
|
:- import_module parse_tree.parse_tree_out.
|
|
:- import_module recompilation.
|
|
:- import_module recompilation.version.
|
|
|
|
:- import_module bool.
|
|
:- import_module list.
|
|
:- import_module getopt_io.
|
|
:- import_module map.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Write out .int3 files.
|
|
%
|
|
|
|
write_short_interface_file_int3(Globals, _SourceFileName, RawCompUnit, !IO) :-
|
|
% This qualifies everything as much as it can given the information
|
|
% in the current module and writes out the .int3 file.
|
|
RawCompUnit = raw_compilation_unit(ModuleName, _, _),
|
|
generate_short_interface_int3(Globals, RawCompUnit, ParseTreeInt3,
|
|
[], Specs0),
|
|
filter_interface_generation_specs(Globals, Specs0, Specs, !IO),
|
|
EffectivelyErrors =
|
|
contains_errors_or_warnings_treated_as_errors(Globals, Specs),
|
|
(
|
|
EffectivelyErrors = no,
|
|
actually_write_interface_file3(Globals, ParseTreeInt3, "", no, !IO),
|
|
touch_interface_datestamp(Globals, ModuleName, ".date3", !IO)
|
|
;
|
|
EffectivelyErrors = yes,
|
|
report_file_not_written(Globals, Specs, no, ModuleName, ".int3",
|
|
no, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Write out .int0 files.
|
|
%
|
|
|
|
write_private_interface_file_int0(Globals, SourceFileName,
|
|
SourceFileModuleName, MaybeTimestamp, RawCompUnit0,
|
|
!HaveReadModuleMaps, !IO) :-
|
|
RawCompUnit0 = raw_compilation_unit(ModuleName, _, _),
|
|
grab_unqual_imported_modules_make_int(Globals, SourceFileName,
|
|
SourceFileModuleName, RawCompUnit0, ModuleAndImports,
|
|
!HaveReadModuleMaps, !IO),
|
|
|
|
% Check whether we succeeded.
|
|
module_and_imports_get_aug_comp_unit(ModuleAndImports, AugCompUnit1,
|
|
GetSpecs, GetErrors),
|
|
GetSpecsEffectivelyErrors =
|
|
contains_errors_or_warnings_treated_as_errors(Globals, GetSpecs),
|
|
( if
|
|
GetSpecsEffectivelyErrors = no,
|
|
set.is_empty(GetErrors)
|
|
then
|
|
% Module-qualify all items.
|
|
% XXX ITEM_LIST We don't need grab_unqual_imported_modules
|
|
% to include in ModuleAndImports and thus in AugCompUnit1
|
|
% any items that (a) generate_private_interface_int0 below
|
|
% will throw away, and (b) which don't help the module qualification
|
|
% of the items that it keeps.
|
|
module_qualify_aug_comp_unit(Globals, AugCompUnit1, AugCompUnit,
|
|
map.init, _EventSpecMap, "", _, _, _, _, _, [], QualSpecs),
|
|
filter_interface_generation_specs(Globals,
|
|
GetSpecs ++ QualSpecs, EffectiveGetQualSpecs, !IO),
|
|
(
|
|
EffectiveGetQualSpecs = [],
|
|
% Construct the `.int0' file.
|
|
generate_private_interface_int0(AugCompUnit, ParseTreeInt0,
|
|
[], GenerateSpecs),
|
|
filter_interface_generation_specs(Globals,
|
|
EffectiveGetQualSpecs ++ GenerateSpecs, Specs, !IO),
|
|
write_error_specs_ignore(Specs, Globals, !IO),
|
|
% Write out the `.int0' file.
|
|
actually_write_interface_file0(Globals, ParseTreeInt0, "",
|
|
MaybeTimestamp, !IO),
|
|
touch_interface_datestamp(Globals, ModuleName, ".date0", !IO)
|
|
;
|
|
EffectiveGetQualSpecs = [_ | _],
|
|
report_file_not_written(Globals, EffectiveGetQualSpecs, no,
|
|
ModuleName, ".int0", no, !IO)
|
|
)
|
|
else
|
|
PrefixMsg = "Error reading interface files.\n",
|
|
report_file_not_written(Globals, GetSpecs, yes(PrefixMsg),
|
|
ModuleName, ".int0", no, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Write out .int and .int2 files.
|
|
%
|
|
|
|
write_interface_file_int1_int2(Globals, SourceFileName, SourceFileModuleName,
|
|
MaybeTimestamp, RawCompUnit0, !HaveReadModuleMaps, !IO) :-
|
|
RawCompUnit0 = raw_compilation_unit(ModuleName, _, _),
|
|
generate_pre_grab_pre_qual_interface_for_int1_int2(RawCompUnit0,
|
|
IntRawCompUnit),
|
|
|
|
% Get the .int3 files for imported modules.
|
|
grab_unqual_imported_modules_make_int(Globals, SourceFileName,
|
|
SourceFileModuleName, IntRawCompUnit, ModuleAndImports,
|
|
!HaveReadModuleMaps, !IO),
|
|
|
|
% Check whether we succeeded.
|
|
module_and_imports_get_aug_comp_unit(ModuleAndImports, AugCompUnit1,
|
|
GetSpecs, GetErrors),
|
|
GetSpecsEffectivelyErrors =
|
|
contains_errors_or_warnings_treated_as_errors(Globals, GetSpecs),
|
|
( if
|
|
GetSpecsEffectivelyErrors = no,
|
|
set.is_empty(GetErrors)
|
|
then
|
|
% Module-qualify all items.
|
|
module_qualify_aug_comp_unit(Globals, AugCompUnit1, AugCompUnit,
|
|
map.init, _, "", _, _, _, _, _, [], QualSpecs),
|
|
filter_interface_generation_specs(Globals,
|
|
GetSpecs ++ QualSpecs, EffectiveGetQualSpecs, !IO),
|
|
(
|
|
EffectiveGetQualSpecs = [],
|
|
% Construct the `.int' and `.int2' files.
|
|
generate_interfaces_int1_int2(Globals, AugCompUnit,
|
|
ParseTreeInt1, ParseTreeInt2, [], GenerateSpecs),
|
|
filter_interface_generation_specs(Globals,
|
|
EffectiveGetQualSpecs ++ GenerateSpecs, Specs, !IO),
|
|
write_error_specs_ignore(Specs, Globals, !IO),
|
|
% Write out the `.int' and `.int2' files.
|
|
actually_write_interface_file1(Globals, ParseTreeInt1, "",
|
|
MaybeTimestamp, !IO),
|
|
actually_write_interface_file2(Globals, ParseTreeInt2, "",
|
|
MaybeTimestamp, !IO),
|
|
touch_interface_datestamp(Globals, ModuleName, ".date", !IO)
|
|
;
|
|
EffectiveGetQualSpecs = [_ | _],
|
|
report_file_not_written(Globals, EffectiveGetQualSpecs, no,
|
|
ModuleName, ".int", yes(".int2"), !IO)
|
|
)
|
|
else
|
|
PrefixMsg = "Error reading .int3 files.\n",
|
|
report_file_not_written(Globals, GetSpecs, yes(PrefixMsg),
|
|
ModuleName, ".int", yes(".int2"), !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred actually_write_interface_file0(globals::in, parse_tree_int0::in,
|
|
string::in, maybe(timestamp)::in, io::di, io::uo) is det.
|
|
|
|
actually_write_interface_file0(Globals, ParseTreeInt0, ExtraSuffix,
|
|
MaybeTimestamp, !IO) :-
|
|
ModuleName = ParseTreeInt0 ^ pti0_module_name,
|
|
construct_int_file_name(Globals, ModuleName, ifk_int0, ExtraSuffix,
|
|
OutputFileName, TmpOutputFileName, !IO),
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals),
|
|
maybe_read_old_int_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
ParseTreeInt0, convert_parse_tree_int0_to_int, MaybeTimestamp,
|
|
MaybeVersionNumbers, !IO),
|
|
ParseTreeInt0V = ParseTreeInt0 ^ pti0_maybe_version_numbers
|
|
:= MaybeVersionNumbers,
|
|
output_parse_tree_int0(NoLineNumGlobals, TmpOutputFileName,
|
|
ParseTreeInt0V, !IO),
|
|
update_interface(Globals, OutputFileName, !IO).
|
|
|
|
:- pred actually_write_interface_file1(globals::in, parse_tree_int1::in,
|
|
string::in, maybe(timestamp)::in, io::di, io::uo) is det.
|
|
|
|
actually_write_interface_file1(Globals, ParseTreeInt1, ExtraSuffix,
|
|
MaybeTimestamp, !IO) :-
|
|
ModuleName = ParseTreeInt1 ^ pti1_module_name,
|
|
construct_int_file_name(Globals, ModuleName, ifk_int1, ExtraSuffix,
|
|
OutputFileName, TmpOutputFileName, !IO),
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals),
|
|
maybe_read_old_int_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
ParseTreeInt1, convert_parse_tree_int1_to_int, MaybeTimestamp,
|
|
MaybeVersionNumbers, !IO),
|
|
ParseTreeInt1V = ParseTreeInt1 ^ pti1_maybe_version_numbers
|
|
:= MaybeVersionNumbers,
|
|
output_parse_tree_int1(NoLineNumGlobals, TmpOutputFileName,
|
|
ParseTreeInt1V, !IO),
|
|
update_interface(Globals, OutputFileName, !IO).
|
|
|
|
:- pred actually_write_interface_file2(globals::in, parse_tree_int2::in,
|
|
string::in, maybe(timestamp)::in, io::di, io::uo) is det.
|
|
|
|
actually_write_interface_file2(Globals, ParseTreeInt2, ExtraSuffix,
|
|
MaybeTimestamp, !IO) :-
|
|
ModuleName = ParseTreeInt2 ^ pti2_module_name,
|
|
construct_int_file_name(Globals, ModuleName, ifk_int2, ExtraSuffix,
|
|
OutputFileName, TmpOutputFileName, !IO),
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals),
|
|
maybe_read_old_int_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
ParseTreeInt2, convert_parse_tree_int2_to_int, MaybeTimestamp,
|
|
MaybeVersionNumbers, !IO),
|
|
ParseTreeInt2V = ParseTreeInt2 ^ pti2_maybe_version_numbers
|
|
:= MaybeVersionNumbers,
|
|
output_parse_tree_int2(NoLineNumGlobals, TmpOutputFileName,
|
|
ParseTreeInt2V, !IO),
|
|
update_interface(Globals, OutputFileName, !IO).
|
|
|
|
:- pred actually_write_interface_file3(globals::in, parse_tree_int3::in,
|
|
string::in, maybe(timestamp)::in, io::di, io::uo) is det.
|
|
|
|
actually_write_interface_file3(Globals, ParseTreeInt3, ExtraSuffix,
|
|
_MaybeTimestamp, !IO) :-
|
|
ModuleName = ParseTreeInt3 ^ pti3_module_name,
|
|
construct_int_file_name(Globals, ModuleName, ifk_int3, ExtraSuffix,
|
|
OutputFileName, TmpOutputFileName, !IO),
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals),
|
|
output_parse_tree_int3(NoLineNumGlobals, TmpOutputFileName,
|
|
ParseTreeInt3, !IO),
|
|
update_interface(Globals, OutputFileName, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred construct_int_file_name(globals::in,
|
|
module_name::in, int_file_kind::in, string::in,
|
|
string::out, string::out, io::di, io::uo) is det.
|
|
|
|
construct_int_file_name(Globals, ModuleName, IntFileKind, ExtraSuffix,
|
|
OutputFileName, TmpOutputFileName, !IO) :-
|
|
Suffix = int_file_kind_to_extension(IntFileKind),
|
|
module_name_to_file_name(Globals, do_create_dirs, Suffix,
|
|
ModuleName, OutputFileName0, !IO),
|
|
OutputFileName = OutputFileName0 ++ ExtraSuffix,
|
|
TmpOutputFileName = OutputFileName ++ ".tmp".
|
|
|
|
:- pred disable_all_line_numbers(globals::in, globals::out) is det.
|
|
|
|
disable_all_line_numbers(Globals, NoLineNumGlobals) :-
|
|
globals.set_option(line_numbers, bool(no),
|
|
Globals, NoLineNumGlobals0),
|
|
globals.set_option(line_numbers_around_foreign_code, bool(no),
|
|
NoLineNumGlobals0, NoLineNumGlobals).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred maybe_read_old_int_and_compare_for_smart_recomp(globals::in,
|
|
T::in, (func(T) = parse_tree_int)::in, maybe(timestamp)::in,
|
|
maybe_version_numbers::out, io::di, io::uo) is det.
|
|
|
|
maybe_read_old_int_and_compare_for_smart_recomp(NoLineNumGlobals,
|
|
ParseTreeIntN, ParseTreeConvert, MaybeTimestamp,
|
|
MaybeVersionNumbers, !IO) :-
|
|
should_generate_item_version_numbers(NoLineNumGlobals,
|
|
WantVersionNumbers, !IO),
|
|
(
|
|
WantVersionNumbers = yes,
|
|
ParseTreeInt = ParseTreeConvert(ParseTreeIntN),
|
|
ModuleName = ParseTreeInt ^ pti_module_name,
|
|
IntFileKind = ParseTreeInt ^ pti_int_file_kind,
|
|
% XXX ITEM_LIST We do this for .int2 files as well as
|
|
% .int and .int0 files. Should we?
|
|
|
|
% Find the timestamp of the current module.
|
|
insist_on_timestamp(MaybeTimestamp, Timestamp),
|
|
% Read in the previous version of the file.
|
|
read_module_int(NoLineNumGlobals,
|
|
"Reading old interface for module", ignore_errors, do_search,
|
|
ModuleName, IntFileKind, _OldIntFileName,
|
|
always_read_module(dont_return_timestamp), _OldTimestamp,
|
|
OldParseTreeInt, _OldSpecs, OldErrors, !IO),
|
|
( if set.is_empty(OldErrors) then
|
|
MaybeOldParseTreeInt = yes(OldParseTreeInt)
|
|
else
|
|
% If we can't read in the old file, the timestamps will
|
|
% all be set to the modification time of the source file.
|
|
MaybeOldParseTreeInt = no
|
|
),
|
|
recompilation.version.compute_version_numbers(Timestamp,
|
|
ParseTreeInt, MaybeOldParseTreeInt, VersionNumbers),
|
|
MaybeVersionNumbers = version_numbers(VersionNumbers)
|
|
;
|
|
WantVersionNumbers = no,
|
|
MaybeVersionNumbers = no_version_numbers
|
|
).
|
|
|
|
:- pred should_generate_item_version_numbers(globals::in, bool::out,
|
|
io::di, io::uo) is det.
|
|
|
|
should_generate_item_version_numbers(Globals, ShouldGenVersionNumbers, !IO) :-
|
|
globals.lookup_bool_option(Globals, generate_item_version_numbers,
|
|
GenerateVersionNumbers),
|
|
io_get_disable_generate_item_version_numbers(DisableVersionNumbers, !IO),
|
|
( if
|
|
GenerateVersionNumbers = yes,
|
|
DisableVersionNumbers = no
|
|
then
|
|
ShouldGenVersionNumbers = yes
|
|
else
|
|
ShouldGenVersionNumbers = no
|
|
).
|
|
|
|
:- pred insist_on_timestamp(maybe(timestamp)::in, timestamp::out) is det.
|
|
|
|
insist_on_timestamp(MaybeTimestamp, Timestamp) :-
|
|
% Find the timestamp of the current module.
|
|
(
|
|
MaybeTimestamp = no,
|
|
unexpected($pred, "timestamp not read with `--smart-recompilation'")
|
|
;
|
|
MaybeTimestamp = yes(Timestamp)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred report_file_not_written(globals::in, list(error_spec)::in,
|
|
maybe(string)::in, module_name::in, string::in, maybe(string)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
report_file_not_written(Globals, Specs, MaybePrefixMsg,
|
|
ModuleName, SuffixA, MaybeSuffixB, !IO) :-
|
|
write_error_specs_ignore(Specs, Globals, !IO),
|
|
(
|
|
MaybePrefixMsg = no
|
|
;
|
|
MaybePrefixMsg = yes(PrefixMsg),
|
|
io.write_string(PrefixMsg, !IO)
|
|
),
|
|
% We use write_error_spec to print the message the interface file or
|
|
% files not being written in order to wrap the message if it is
|
|
% longer than the line length.
|
|
module_name_to_file_name(Globals, do_not_create_dirs, SuffixA,
|
|
ModuleName, IntAFileName, !IO),
|
|
(
|
|
MaybeSuffixB = no,
|
|
NotWrittenPieces = [quote(IntAFileName), words("not written."), nl]
|
|
;
|
|
MaybeSuffixB = yes(SuffixB),
|
|
module_name_to_file_name(Globals, do_not_create_dirs, SuffixB,
|
|
ModuleName, IntBFileName, !IO),
|
|
NotWrittenPieces = [quote(IntAFileName), words("and"),
|
|
quote(IntBFileName), words("not written."), nl]
|
|
),
|
|
NotWrittenMsg = error_msg(no, treat_as_first, 0,
|
|
[always(NotWrittenPieces)]),
|
|
NotWrittenSpec = error_spec($pred, severity_informational,
|
|
phase_read_files, [NotWrittenMsg]),
|
|
write_error_spec_ignore(NotWrittenSpec, Globals, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.write_module_interface_files.
|
|
%---------------------------------------------------------------------------%
|