The new --warn-unneeded-initial-statevar option asks the compiler
to warn about code such as
pred_a(!.X, ...) :-
... code that uses !.X, but does not update it ...
In this case, the preferred fix is to just replace all occurrences
of !.X with X.
The new --warn-unneeded-final-statevar option asks the compiler
to warn about code such as
pred_a(!X, ...) :-
... code that maybe uses !.X, but does not update it ...
In this case, the preferred fix also involves replacing all occurrences
of !.X with X, but it also involves either deleting the argument
containing !:X (the best option), or, if there is some reason why
the predicate's signature must stay unchanged, to replace !:X with X as well.
And if the clause body does not actually refer to either !.X or !:X, then
*both* arguments represented by !X should be deleted.
The first option is a style warning; the second option, due to the
signature change it may call for, is a non-style warning.
Both options have a version whose name adds a "-lambda" suffix, and which
does the same warnings for the heads of lambda expressions, not clauses.
Note that several of the modules below, including some that help to implement
the warnings, also contain code changes that result from *acting* on
the new warnings, e.g. by deleting unneeded statevar arguments.
Other, similar changes will also come after this diff is committed.
compiler/options.m:
doc/user_guide.texi:
Document the new options.
compiler/state_var.m:
Gather the information needed to decide what code merits the new warnings.
Do so in three stages:
- when processing the head of a clause or of a lambda expression,
- when processing the body goal of that clause or lambda expression,
- when finishing up the processing of the clause or lambda expression.
Add a predicate to generate the warnings for lambda expressions.
Do not generate the warnings for clauses. This is because whether or not
we want to warn about state vars in some clauses depends on the properties
of *other* clauses of the same predicate, and state_var.m has access
to only one clause at a time. Instead,
- return the info needed by the warning-generating code in pre_typecheck.m
(one of the first passes we execute after adding all clauses
to the HLDS), and
- we export some functionality for use by that code.
Switch to a convention for naming the program variables corresponding
to the middle (non-initial, non-final) versions of state variables
whose output is affected by changes in the code of the clause body goal
only if they involve that specific state variable.
Give some predicates more descriptive names.
compiler/make_hlds.m:
Make state_var.m and its new functionality visible from outside
the make_hlds package.
compiler/add_clause.m:
Record the information gathered by state_var.m in each clause.
compiler/hlds_clauses.m:
Add a slot to each clause for this information.
Give some predicates more descriptive names.
compiler/headvar_names.m:
Use the contents of the new slots to detect whether any clauses
have unused state vars, and if so, return the chosen consensus names
of the head vars to the code of pre_typecheck.m, which uses this info
as part of the implementation of the new warnings.
compiler/pre_typecheck.m:
Implement the new warnings.
compiler/mercury_compile_front_end.m:
Record the warnings that pre_typecheck.m can now return.
compiler/error_spec.m:
compiler/write_error_spec.m:
Add unsigned versions of the format pieces involving ints, for use
by the new code in pre_typecheck.m, and implement them.
compiler/hlds_out_util.m:
compiler/maybe_util.m:
Move two related types from hlds_out_util.m to maybe_util.m,
in order to allow pre_typecheck.m to use one of them.
compiler/hlds_args.m:
Add a new utility function for use by the new code above.
compiler/foreign.m:
Act on the new warnings by deleting the long-unused predicates
being warned about.
compiler/post_typecheck.m:
Speed up this traversal. (I originally thought to implement
the new warnings in this pass.)
compiler/add_foreign_proc.m:
compiler/add_pragma.m:
compiler/add_pragma_tabling.m:
compiler/add_pragma_type_spec.m:
compiler/add_pred.m:
compiler/add_type.m:
compiler/build_mode_constraints.m:
compiler/call_gen.m:
compiler/check_typeclass.m:
compiler/clause_to_proc.m:
compiler/code_loc_dep.m:
compiler/delay_info.m:
compiler/delay_partial_inst.m:
compiler/dense_switch.m:
compiler/det_check_goal.m:
compiler/det_infer_goal.m:
compiler/disj_gen.m:
compiler/du_type_layout.m:
compiler/format_call.m:
compiler/goal_expr_to_goal.m:
compiler/hlds_dependency_graph.m:
compiler/hlds_out_pred.m:
compiler/hlds_pred.m:
compiler/hlds_rtti.m:
compiler/inst_merge.m:
compiler/instance_method_clauses.m:
compiler/intermod.m:
compiler/interval.m:
compiler/ite_gen.m:
compiler/lookup_switch.m:
compiler/make_hlds_passes.m:
compiler/mark_tail_calls.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mode_errors.m:
compiler/parse_string_format.m:
compiler/passes_aux.m:
compiler/polymorphism.m:
compiler/polymorphism_info.m:
compiler/polymorphism_type_info.m:
compiler/pragma_c_gen.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/quantification.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_conj.m:
compiler/string_switch.m:
compiler/superhomogeneous.m:
compiler/switch_gen.m:
compiler/tag_switch.m:
compiler/type_constraints.m:
compiler/typecheck.m:
compiler/typecheck_clauses.m:
compiler/typecheck_coerce.m:
compiler/typecheck_error_unify.m:
compiler/unify_gen_deconstruct.m:
compiler/unify_proc.m:
compiler/var_origins.m:
Conform to the changes above, and/or act on the new warnings.
browser/diff.m:
library/bit_buffer.m:
library/getopt.m:
library/getopt_io.m:
library/io.error_util.m:
library/io.file.m:
library/mercury_term_lexer.m:
library/parsing_utils.m:
library/pretty_printer.m:
library/robdd.m:
library/rtti_implementation.m:
library/string.builder.m:
library/string.parse_runtime.m:
mdbcomp/feedback.m:
Act on the new warnings.
tests/hard_coded/sv_nested_closures.m:
Change this test's code to avoid the new warnings, since
(if --halt-at-warn is ever enabled) the warnings would interfere
with its job .
tests/invalid/bug197.err_exp:
tests/invalid/bug487.err_exp:
tests/invalid/nullary_ho_func_error.err_exp:
tests/invalid/try_detism.err_exp:
tests/warnings/singleton_test_state_var.err_exp:
Expect variable names for the middle versions of state vars
using the new naming scheme.
compiler/hlds_out_goal.m:
Keep the existing exported predicates of this module that do I/O,
but change its internals to operate using string builders.
compiler/hlds_out_mode.m:
compiler/hlds_out_util.m:
compiler/indent.m:
compiler/parse_tree_out_term.m:
Export versions of existing predicates that operate using string builders.
library/string.builder.m:
Add a new predicate, append_strings_sep, which differs from the
existing append_strings predicate by adding a separator between strings.
NEWS.md:
Announce the new predicate.
library/string.builder.m:
Add the predicate string.builder.format. We already have
string.writer.format, one of whose instances, the one for
string.builder.{handle,state}, does a string.format and adds
the resulting string to the given string builder. The new predicate
allows this to be done directly, without the type class overhead
(both conceptual overhead, and compilation time overhead) in cases
where the generality of type class is not needed, and in a way that
allows format strings in direct calls to string.builder.format
to be parsed and interpreted at compile-time, the same way as we
already do for calls to e.g. io.format.
NEWS.md:
Announce the new predicate.
compiler/format_call.m:
Specialize calls to string.builder.format. Use the code that specializes
calls to io.format, after suitable generalization.
compiler/builtin_lib_types.m:
mdbcomp/builtin_modules.m:
Add convenience functions needed by new code in format_call.m.
compiler/get_dependencies.m:
In the presence of (potential) calls to string.builder.format,
implicitly import the modules that define the predicates that
format_call.m may now generate calls to.
compiler/introduced_call_table.m:
List string.builder.append_string as a predicate that format_call.m
may now introduce calls to.
tests/hard_coded/test_builder_format.{m,exp}:
A new test case to test the new functionality.
tests/hard_coded/Mmakefile:
Enable the new test case.
tests/warnings/format_call_warning.m:
Fix indentation.
library/char.m:
Define predicates and/or functions to implement instance methods.
Document why implementations of {to,from}_int differ so much
from the implementations of {to,from}_uint.
Group the foreign_procs implementing to_int first by mode, and then
by language, instead of the other way around.
library/bitmap.m:
library/digraph.m:
library/string.builder.m:
library/term.m:
Define predicates and/or functions to implement instance methods.
library/string.builder.m:
Add a predicate that tests whether the total length of the string
implicit in a string builder is within a limit, or not.
Add a function that returns that total length.
NEWS.md:
Announce the new predicate and function.
compiler/parse_tree_out_term.m:
Use the new predicate to optimize a test.
compiler/parse_tree_out_info.m:
... by making string builders instances of the "output" typeclass,
whose operations are the base level of the code of parse_tree_out*.m.
Strings were already instances of "output", but the use of this instance
was problematic for large structures such as entire files. This is because
if the final string was constructed by adding together N atomic strings,
then the construction of the final string involves copying each of those
atomic strings about N/2 times on average.
With the string builder instance, each string is copied just twice:
when it is added to the string builder state, and when that state is
converted to the final string.
library/string.builder.m:
Add three new predicates, append_char, append_string and append_strings.
The first two are copied from existing instance methods; making them
separate predicates allows them to be invoked using a first order call,
instead of a method call. The third is just for convenience. All three
are used by the new code in parse_tree_out_info.m.
NEWS.md:
Announce the new predicates in string.builder.m.
library/term_io.m:
library/stream.string_writer.m:
Many predicates in these two modules have long had two typeclass
constraints:
stream.writer(Stream, string, State)
stream.writer(Stream, char, State)
This diff eliminates the second constraint, for two reasons.
The first is ergonomics; writing one constraint is faster than writing two,
and likewise for reading. The second is efficiency: we have to pass around
just one typeclass info, not two.
There is a tradeoff, which is that to output characters, we now
have to call char_to_string. For the string.builder instance of
stream.writer, this has no efficiency downside, because the char instance
of stream.string_writer itself calls char_to_string. For the I/O state
instance of stream.string_writer, there is a downside because io.write_char
does not need to convert the character to a string, but the downside
is negligible compared to the overall cost of I/O. And in any case,
most of the places where the code of either of these modules wrote out
characters, it wrote out character *constants*, which this diff converts
to string constants, eliminating the runtime conversion and its cost.
library/string.builder.m:
Use string.char_to_string, instead of its older synonym string.from_char,
in the char instance of stream.string_writer.
library/term_io.m:
Move the base operations of term_io.m to the structure we use
in parse_tree_out*.m in the compiler, where for every type X,
there is a function X_to_string, and two predicates write_X and format_X,
with the former operating on I/O states, and the latter operating on
arbitrary streams. The idea is to apply the "don't repeat yourself"
principle by having both X_to_string and write_X just call format_X.
Apply that principle here as well, with one minor exception,
which is that for some values of X, both write_X and format_X are
implemented in terms of X_to_string.
Impose the X_to_string, write_X, format_X naming scheme. The ancient code
already in term_io.m had (each for some values of X) had
- some of these functions/predicates missing
- inconsistent names, in that write_X/N did I/O while write_X/(N+1)
wrote to arbitrary streams
- names that were inconsistent in another way, in that write_X/N did
I/O of values of type X, but the function to convert X to string
was NOT named X_to_string.
Keep some of the misnamed functions around permanently, because
some of the names for fitting into the new scheme, such as
"escaped_string_to_string", would be strange.
Keep the rest of the misnamed functions and all the misnamed predicates
around temporarily, with commented-out obsolete pragmas. I expect
to make these pragmas active when the rest of term_io.m is converted
to this scheme.
To prepare for that, use string.builder, not string, as the
stream.writer instance to implement X_to_string, because of its
better algorithmic complexity, which is needed mainly for terms
of nontrivial size.
Consistently put operations on each X in the order X_to_string,
write_X and format_X.
NEWS.md:
List all the new predicates and functions.
configure.ac:
Require the installed compiler to contain the fix which allows
a typespec pragma for an obsolete predicate or function.
browser/interactive_query.m:
compiler/hlds_out_util.m:
compiler/parse_tree_out_clause.m:
compiler/parse_tree_out_cons_id.m:
compiler/parse_tree_out_info.m:
compiler/parse_tree_out_pragma.m:
compiler/parse_tree_out_sym_name.m:
compiler/parse_tree_out_type_repn.m:
library/pretty_printer.m:
library/stream.string_writer.m:
library/string.builder.m:
mdbcomp/trace_counts.m:
Update all references to the newly-obsolete predicates and functions.
library/string.to_string.m:
Improve variable names.
Discussion of these changes can be found on the Mercury developers
mailing list archives from June 2018.
COPYING.LIB:
Add a special linking exception to the LGPL.
*:
Update references to COPYING.LIB.
Clean up some minor errors that have accumulated in copyright
messages.
Estimated hours taken: 0.5
Branches: main.
Move the string builder stream from extras to the standard library.
library/string.builder.m:
Move stream_util.string_builder to string.builder.
Use builtin.copy instead of unsafe_promise_unique in the implementation
of put/4 for the string builder stream.
library/string.m:
Include string.builder.
tests/hard_coded/Mmakefile:
tests/hard_coded/string_builder_test.exp:
tests/hard_coded/string_builder_test.m:
Add a test case.
extras/Mmakefile:
extras/README:
extras/stream/Mmakefile:
extras/stream/README:
extras/stream/impure.m:
extras/stream/lowlevel.m:
extras/stream/stream_old.m:
extras/stream/stream_util.m:
extras/stream/stream_util.string_builder.m:
extras/stream/tests/Makefile:
extras/stream/tests/stream_util_test.exp:
extras/stream/tests/stream_util_test.m:
Completely remove the streams modules from extras. These modules
are all deprecated now.