compiler/typecheck_errors.m:
Improve the diagnostics we generate for mismatches between actual and
expected types. If the mismatch was between a single actual type and
a single expected type, we already printed a message whose format
was specialized for that case, but in every other case, we fell back
to a more general but less readable error message template. Improve on this
by splitting the task into two halves, one for the actual type(s) and one
for the expected type(s), each of which generates simpler text if
there is only one such type.
Separate the actual type part of the diagnostic from the expected type part
using a semicolon instead of a comma, because we now use commas to
separate multiple actual types from each other, and multiple expected
types from each other.
Don't insist on putting a newline after the "type error:" part of the
diagnostic.
Do all of the above in just one predicate, factoring out code that
used to be duplicated.
Delete a function that has never been used. (I added it around 2008
for later use by a student working on software transactional memory,
but that use never happened.) This used to contain a third copy
of the code that was factored out.
For functions that used to take both a typecheck_info and a
type_error_clause_context, delete the latter argument, since the caller
invariably took it out of the typecheck_info that it also passed.
compiler/typecheck.m:
Don't pass now-unneeded type_error_clause_contexts.
compiler/typecheck_error_type_assign.m:
Fix typo in a field name.
tests/invalid/abstract_eqv.err_exp:
tests/invalid/actual_expected.err_exp:
tests/invalid/actual_more_expected.err_exp:
tests/invalid/bug197.err_exp:
tests/invalid/ext_type_bug.err_exp:
tests/invalid/fbnf.err_exp:
tests/invalid/foreign_procs_exist_type.err_exp:
tests/invalid/higher_order_mode_mismatch.err_exp:
tests/invalid/integral_constant_no_suffix.err_exp:
tests/invalid/method_impl.err_exp:
tests/invalid/mixed_up_streams.err_exp:
tests/invalid/try_bad_params.err_exp:
tests/invalid/type_diff.err_exp:
tests/invalid/type_error_ambiguous.err_exp:
tests/invalid/types2.err_exp:
tests/invalid_nodepend/errors2.err_exp:
tests/invalid_purity/impure_pred_t1_fixed.err_exp:
tests/invalid_purity/impure_pred_t2.err_exp:
tests/invalid_purity/purity_nonsense.err_exp:
tests/invalid_purity/purity_nonsense2.err_exp:
Update expected error messages.
The compiler's diagnostic outputs often contain terms, representing
either terms in the program, or other entities such as types or modes.
These can be printed either as
f(a, b)
or as
f(
a,
b
)
We usually want the former if the term fits on one line, but the latter
if it is too big to fit on one line. The problem is that the code
generating the diagnostic often does not know what fits on one line.
compiler/error_spec.m:
This diff adds two new format pieces that respectively stand for
each half of a matched pair of left and right parentheses.
The idea is that these can be printed
- either with a newline, and an indent increment, after the left paren,
and an indent decrement, and a newline, before the right paren,
and with all newlines being honored between them,
- or with no newline after the left paren or before the right paren,
and all newlines between them being replaced by spaces.
compiler/write_error_spec.m:
Implement the new format pieces, using the one-line format above
if the term fits in the space available, or the multi-line format
if it does not.
compiler/error_type_util.m:
Use the new mechanism to represent the structure of types.
Delete an old piece of code that had the same objective,
but was much cruder and less effective.
tests/invalid/actual_expected.err_exp:
tests/invalid/ext_type_bug.err_exp:
tests/invalid/fbnf.err_exp:
tests/invalid/ho_type_arity_bug.err_exp:
tests/invalid/overloading.err_exp:
tests/invalid/type_diff.err_exp:
Expect more compact representations of the structure of types.
tests/invalid/type_error_ambiguous.err_exp:
Expect a different ordering of the same information.
The difference is due to the changed internal representation
(in terms of format_pieces) of a type.
compiler/error_util.m:
Rewrite the type_to_pieces function, which typecheck_errors.m uses
to format types in error messages, in order to fix five problems.
The first two problems were with formatting higher order types.
First, if a higher order type included an existentially quantified
type variable, that quantification was *not* printed around the
higher order type. Second, that quantification *was* printed around
the type of every (non-higher-order) argument of the higher order value.
The only reason why this has not been a problem so far is that
we have no test case that contains a higher order type with an
existentially quantified type variable :-(
The fix to both these problems is to always put the existential
quantification of any such type variables at the top level, regardless
of the kind of type the quantification ranges over, and to never print
any quantification of any of its component types.
The third problem was that non-higher-order types were output in a
non-structured fashion. (The special-case code we used to format
higher order types did already output *them* in a structured fashion,
though only at the top level.) We did this by converting (unparsing)
the type to a term, and then calling mercury_term_to_string.
Generating structured output by replacing only the mercury_term_to_string
part would not worked well; most of the code would have been devoted
to working out what kind of type the given term was representing.
Therefore this diff changes the approach to formatting types without
converting them to a term. The output we generate for each type
uses indentation levels to show the type's structure, but for
types whose formatted form is sufficiently short, we delete all
the newlines from that representation.
The fourth problem was while most of the existing code took care
to treat function names as unbreakable, one part of it did not,
which caused the name of a field update function, "f1 :=",
to be split across two lines. This diff fixes that bug as well.
A fifth problem, pointed out by Peter, was that we were printing
arity-0 functions as "func" instead of as "(func)", even though
Mercury syntax for types demands the latter.
An arguable sixth problem was that we formatted existential
quantifications as
(some [Vars] Type)
We now format that as
some [Vars] (Type)
Change the order of the arguments of type_to_pieces to reduce
the difference between it and type_pieces, its internal version,
which we use to format types that do not need existential quantification.
Export the function that filters newlines out of lists of format
components, since other parts of the compiler may also need it
in the future.
Fix two occurrences of a bug that is totally unrelated to the above:
list_to_pieces and strict_list_to_pieces treated the last element
in their input list differently from all the other elements.
compiler/parse_tree_out_term.m:
Add a utility function for use by new code in error_util.m.
compiler/typecheck_errors.m:
Conform to the new argument order of type_to_pieces.
tests/invalid/actual_expected.err_exp:
tests/invalid/bug197.err_exp:
tests/invalid/ext_type.err_exp:
tests/invalid/ext_type_bug.err_exp:
tests/invalid/foreign_procs_exist_type.err_exp:
tests/invalid/higher_order_mode_mismatch.err_exp:
tests/invalid/ho_type_arity_bug.err_exp:
tests/invalid/no_method.err_exp:
tests/invalid/nullary_ho_func_error.err_exp:
tests/invalid/overloading.err_exp:
tests/invalid/type_error_ambiguous.err_exp:
tests/invalid/type_mismatch.err_exp:
tests/invalid/types2.err_exp:
tests/invalid/user_field_access_decl_override2.err_exp:
tests/invalid_purity/impure_func_t5.err_exp:
tests/invalid_purity/impure_pred_t1.err_exp:
tests/invalid_purity/impure_pred_t1_fixed.err_exp:
tests/invalid_purity/impure_pred_t2.err_exp:
Expect types in error messages in their updated format.
compiler/mode_errors.m:
When generating an error message for a bad higher order inst,
print the specific cause of the mismatch, instead of just
"actual inst is X, expected inst was Y".
compiler/modecheck_call.m:
Change the code that generates that error to record the specific cause
in the mode_error structure of the error.
tests/invalid/higher_order_mode_mismatch.{m,err_exp}:
Add a new test case for the specific causes that other test cases
don't already cover. (As it happens, most of those causes can't be
caught by mode analysis because typechecking reports them first,
but it did so in ways that could be improved. Hence the change to
typecheck_errors.m and most of the .err_exp files below.)
tests/invalid/Mmakefile:
Enable the new test case.
compiler/typecheck_errors.m:
Instead of generating output of the form
<something> has type `abc',
expected type was `def'
generate output of the form
<something> has type
abc,
expected type was
def
The indentation directs the eye to the differences that matter,
and automatically lines up any corresponding parts of the actual
and expected types. It also replaces the quotes as a method
of separating the types being referred to from their surroundings.
tests/invalid/abstract_eqv.err_exp:
tests/invalid/actual_expected.err_exp:
tests/invalid/anys_in_negated_contexts.err_exp:
tests/invalid/arg_permutation.err_exp:
tests/invalid/bad_statevar_bad_context.err_exp:
tests/invalid/bug197.err_exp:
tests/invalid/comparison.err_exp:
tests/invalid/error_in_list.err_exp:
tests/invalid/ext_type.err_exp:
tests/invalid/ext_type_bug.err_exp:
tests/invalid/foreign_procs_exist_type.err_exp:
tests/invalid/getopt_old.err_exp:
tests/invalid/ho_type_arity_bug.err_exp:
tests/invalid/ho_type_mode_bug.err_exp:
tests/invalid/illtyped_compare.err_exp:
tests/invalid/integral_constant_no_suffix.err_exp:
tests/invalid/method_impl.err_exp:
tests/invalid/mixed_up_streams.err_exp:
tests/invalid/mpj1.err_exp:
tests/invalid/mpj4.err_exp:
tests/invalid/no_method.err_exp:
tests/invalid/nullary_ho_func_error.err_exp:
tests/invalid/overloading.err_exp:
tests/invalid/record_syntax_errors.err_exp:
tests/invalid/try_bad_params.err_exp:
tests/invalid/type_error_ambiguous.err_exp:
tests/invalid/type_error_in_arg.err_exp:
tests/invalid/type_mismatch.err_exp:
tests/invalid/types2.err_exp:
tests/invalid/user_field_access_decl_override2.err_exp:
tests/invalid_nodepend/errors2.err_exp:
tests/invalid_purity/impure_func_t5.err_exp:
tests/invalid_purity/impure_pred_t1.err_exp:
tests/invalid_purity/impure_pred_t1_fixed.err_exp:
tests/invalid_purity/impure_pred_t2.err_exp:
tests/invalid_purity/purity_nonsense2.err_exp:
tests/invalid_purity/purity_type_error.err_exp:
Expect the updated error messages.
tests/invalid/ho_type_mode_bug.m:
Update obsolete comments.
compiler/typecheck_errors.m:
Improve diagnostics for some type errors in two separate ways.
First, when printing an error message for a type mismatch,
replace messages of the form
... has type T1,
expected type was T2
with messages of the form
... has type
T1,
expected type was
T2.
This way, the types both (a) stand out from the rest of the message,
and (b) any corresponding parts will line up, making discrepancies
easier to see.
Second, avoid messages of the form
... has type `some [T] T'
expected type was `some [T] T'.
which can be both baffling and infuriating, by including the variable
numbers of the type variables if this is needed to make two different
types *visibly* different, yielding messages such as
... has type
`some [T_2] T2',
expected type was
`some [T_3] T3'.
which can still be baffling, in the absence of any info about where T_2
and T_3 came from, but at least should not be infuriating, since it
*does* show a difference between actual and expected.
compiler/error_util.m:
Provide the infrastructure for the second part, by letting callers
control how type variables are printed.
tests/invalid/actual_expected.err_exp:
tests/invalid/bug197.err_exp:
tests/invalid/coerce_ambig.err_exp:
tests/invalid/ext_type_bug.err_exp:
tests/invalid/foreign_procs_exist_type.err_exp:
tests/invalid_purity/impure_pred_t1_fixed.err_exp:
tests/invalid_purity/impure_pred_t2.err_exp:
tests/invalid_purity/purity_nonsense.err_exp:
tests/invalid_purity/purity_nonsense2.err_exp:
Expect the updated error messages.
tests/invalid/*.{m,err_exp}:
tests/misc_tests/*.m:
tests/mmc_make/*.m:
tests/par_conj/*.m:
tests/purity/*.m:
tests/stm/*.m:
tests/string_format/*.m:
tests/structure_reuse/*.m:
tests/submodules/*.m:
tests/tabling/*.m:
tests/term/*.m:
tests/trailing/*.m:
tests/typeclasses/*.m:
tests/valid/*.m:
tests/warnings/*.{m,exp}:
Make these tests use four-space indentation, and ensure that
each module is imported on its own line. (I intend to use the latter
to figure out which subdirectories' tests can be executed in parallel.)
These changes usually move code to different lines. For the tests
that check compiler error messages, expect the new line numbers.
browser/cterm.m:
browser/tree234_cc.m:
Import only one module per line.
tests/hard_coded/boyer.m:
Fix something I missed.
compiler/typecheck_errors.m:
Add a mechanism to allow the specification of a called predicate not just
by simple_call_id, in which the sym_name is the original sym_name
in the call, which may be unqualified, but by pred_id, through which
we can always look up the predicate's module qualified name.
compiler/typecheck.m:
Use that mechanism when the called predicate is uniquely known.
Give a predicate a better name.
tests/invalid/comparison.{m,err_exp}:
tests/invalid/Mmakefile:
Add and enable the motivating test case.
tests/invalid/*.err_exp:
Update other expected output files reporting type errors in calls.
Branches: main, 11.01
Fix a couple of issues with some of the set types in the standard library
being used in type class instances.
library/set_unordlist.m:
Define set_unordlists using a notag type rather than an equivalence.
This allows them to be safely used in type class instances.
library/set.m:
Export the definition of the type set/1 in an undocumented interface
section. Not exporting it leads to problems when it used used in
type class instances (since it is defined using an abstract
equivalence). We don't want to use a notag wrapper here since that
would lead to some operations, e.g. power_union/2, being less efficient.
This should be ok; the abstraction barrier is still in place since set/1
is defined to be set_ordlist/1 (which is itself abstract).
tests/invalid/actual_expected.err_exp:
tests/invalid/overloading.err_exp:
Conform to the above changes.
Branches: main
compiler/mercury_to_mercury.m:
Don't write an outer pair of brackets when formatting terms with '.'
or ':' as the functor, which made module-qualified types in error
messages unnecessarily ugly.
tests/hard_coded/impl_def_literal.exp:
tests/invalid/actual_expected.err_exp:
tests/invalid/bad_instance.err_exp:
tests/invalid/errors2.err_exp:
tests/invalid/ext_type.err_exp:
tests/invalid/ext_type_bug.err_exp:
tests/invalid/funcs_as_preds.err_exp:
tests/invalid/illtyped_compare.err_exp:
tests/invalid/instance_dup_var.err_exp:
tests/invalid/invalid_instance_declarations.err_exp:
tests/invalid/method_impl.err_exp:
tests/invalid/mixed_up_streams.err_exp:
tests/invalid/mpj4.err_exp:
tests/invalid/nullary_ho_func_error.err_exp:
tests/invalid/overloading.err_exp:
tests/invalid/purity/impure_func_t5.err_exp:
tests/invalid/purity/impure_pred_t1.err_exp:
tests/invalid/purity/impure_pred_t1_fixed.err_exp:
tests/invalid/purity/impure_pred_t2.err_exp:
tests/invalid/record_syntax_errors.err_exp:
tests/invalid/tc_err1.err_exp:
tests/invalid/tc_err2.err_exp:
tests/invalid/try_bad_params.err_exp:
tests/invalid/type_error_ambiguous.err_exp:
tests/misc_tests/pretty_print_test.exp:
tests/warnings/inference_test.exp:
Update test cases.
Estimated hours taken: 3
Branches: main
compiler/typecheck_errors.m:
When printing error messages about mismatches between actual and
expected types, eliminate duplicates not on the basis of the raw
data, but on the basis of what is to be printed. This is an
improvement, because irrelevant differences in the raw data (e.g. the
numbers of variables in varsets) were causing us to print duplicates.
tests/invalid/actual_expected.{m,err_exp}:
New test case to test the new error message. It is an extract from
use_local_vars.m, which is where I found the problem.
tests/invalid/Mmakefile:
Enable the new test case.