Commit Graph

15 Commits

Author SHA1 Message Date
Zoltan Somogyi
660cfe4f83 s/predicate symbol predicate/predicate symbol/ in a diagnostic.
We used to generate diagnostics of the form

    The predicate symbol predicate `<'/2 is also overloaded here.

The second "predicate" is pure noise. It could never be "function",
even though the code generating that message was prepared for that.

compiler/typecheck.m:
    When typechecking a *predicate* call, don't specify the predicate
    being called using a data structure that can also refer to functions.

compiler/typecheck_info.m:
    When representing an overloaded predicate name, as opposed to
    an overloaded function name, don't include a pred_or_func indication
    that should *always* be pf_predicate.

compiler/typecheck_errors.m:
    When reporting an overloaded predicate name, or talking about a
    predicate's argument vector, do not take a pred_or_func indication,
    since it should *always* be pf_predicate.

tests/invalid/ambiguous_overloading_error.err_exp:
tests/warnings/ambiguous_overloading.exp:
    Don't expect the redundant "predicate" in the overload error message.

tests/invalid/max_error_line_width.err_exp:
tests/invalid/max_error_line_width.m:
    The deletion of the redundant "predicate" in overload error messages
    made them all fit on one line, robbing this test of its task of testing
    longer-than-80-column output lines. Change the test so that the overload
    is not between int.< and float.<, but between the unchecked_left_shift
    functions in int and uint, since the longer function name yields error
    message lines in the length range this test case wants to test.

tests/invalid/ambiguous_overloading_error.m:
tests/invalid/arg_permutation.m:
tests/invalid/assert_in_interface.m:
tests/invalid/bad_detism_category.m:
    Fix programming style.

tests/invalid/assert_in_interface.err_exp:
    Update a line number.
2020-10-26 20:28:18 +11:00
Zoltan Somogyi
9789375cc5 Make pre-HLDS passes use file-kind-specific parse trees.
Replacing item blocks file-kind-specific kinds of section markers with
file-kind-specific parse trees has several benefits.

- It allows us to encode the structural invariants of each kind of file
  we read in within the type of its representation. This makes the detection
  of any accidental violations of those invariants trivial.

- Since each file-kind-specific parse tree has separate lists for separate
  kinds of items, code that wants to operate on one or a few kinds of items
  can just operate on those kinds of items, without having to traverse
  item blocks containing many other kinds of items as well. The most
  important consequence of this is not the improved efficiency, though
  that is nice, but the increased clarity of the code.

- The new design is much more flexible. For example, it should be possible
  to record that e.g. an interface file we read in as a indirect dependency
  (i.e. a file we read not because its module was imported by the module
  we are compiling, but because its module was imported by *another* imported
  module) should be used *only* for the purpose it was read in for. This should
  avoid situations where deleting an import of A from a module, because it
  is not needed anymore, leads the compiler to generate an error message
  about a missing import of module B. This can happen if (a) module B
  always *should* have been imported, since it is used, but (b) module A's
  import of module B lead to module B's interface being available *without*
  an import of B.

  Specifically, this flexibility should enable us to establish each module's
  .int file as the single source of truth about how values of each type
  defined in that module should be represented. When compiling each source
  file, this approach requires the compiler to read in that module's .int file
  but using only the type_repn items from that .int file, and nothing else.

- By recording a single parse tree for each file we have read, instead of
  a varying number of item blocks, it should be significantly easier to
  derive the contents of .d files directly from the records of those
  parse trees, *without* having to maintain a separate set of fields
  in the module_and_imports structure for that purpose. We could also
  trivially avoid any possibility of inconsistencies between these two
  different sources of truth. (We currently fill in the fields used to
  drive the generation of .d files using two different pieces of code,
  one used for --generate-dependencies and one used for all other invocations,
  and these two *definitely* generate inconsistent results, as the significant
  differences in .d files between (a) just after an invocation of
  --generate-dependencies and (b) just after any other compiler invocation
  can witness.)

This change is big and therefore hard to review. Therefore in many files,
this change adds "XXX CLEANUP" comments to draw attention to places that
have issues that should be fixed, but whose fixes should come later, in
separate diffs.

compiler/module_imports.m:
    The compiler uses the module_and_imports structure defined here
    to go from a raw compilation unit (essentially a module to be compiled)
    to an augmented compilation unit (a raw compilation unit together
    with all the interface and optimization files its compilation needs).
    We used to store the contents of both the source file and of
    the interface and optimization files in the module_and_imports structure
    as item blocks. This diff replaces all those item blocks with
    file-kind-specific parse trees, for the reasons mentioned above.

    Separate out the .int0 files of ancestors modules from the .intN
    files for N>0 of directly imported modules. (Their item blocks
    used to be stored in the same list.)

    Maintain a database of the source, interface and optimization files
    we have read in so far. We use it to avoid reading in interface files
    if we have already read in a file for the same module that contains
    strictly more information (either an interface file with a smaller
    number as a suffix, or the source file itself).

    Shorten some field names.

compiler/prog_item.m:
    Define data structures for storing information about include_module,
    import_module and use_module declarations, both in a form that allows
    the representation of possibly erroneous code in actual source files,
    and in checked-and-cleaned-up form which is guaranteed to be free
    of the relevant kinds of errors. Add a block comment at the start
    of the module about the need for this distinction.

    Define parse_tree_module_src, a data structure for representing
    the source code of a single module. This is different from the existing
    parse_tree_src type, which represents the contents of a single source file
    but which may contain *more* than one module, and also different from
    a raw_compilation_unit, which is based on item blocks and is thus
    unable to express to invariants such as "no clauses in the interface".

    Modify the existing parse_tree_intN types to express the distinction
    mentioned just above, and to unify them "culturally", i.e. if they
    store the same information, make them store it using the same types.

    Fix a mistake by allowing promises to appear in .opt files.
    I originally ruled them out because the code that generates .opt files
    does not have any code to write out promises, but some of the predicates
    whose clauses it writes out have goal_type_promise, which means that
    they originated as promises, and get written out as promises.

    Split the existing pragma item kind into three item kinds, which have
    different invariants applying to them.

    - The decl (short for declarative) pragmas give the compiler some
      information, such as that a predicate is obsolete or that we
      want to type specialize some predicate or function, that is in effect
      part of the module's interface. Decl pragmas may appear in module
      interfaces, and the compiler may put them into interface files;
      neither statement is true of the other two kinds of pragmas.

    - The impl (short for implementation) pragmas are named so
      precisely because they may appear only in implementation sections.
      They give the compiler information that is private to that module.
      Examples include foreign_decls, foreign_codes, foreign_procs,
      and promises of clause equivalence, and requests for inlining,
      tabling etc. These will never be put into interface files,
      though some of them can affect the compilation of other modules
      by being included in .opt files.

    - The gen (short for generated) pragmas can never (legally) appear
      in source files at all. They record the results of compiler
      analyses e.g. about which arguments of a predicate are unused,
      or what exceptions a function can throw, and accordingly they
      should only ever occur in compiler-generated interface files.

    Use the new type differences between the three kinds of pragmas
    to encode the above invariants about which kinds of pragmas can appear
    where into the various kinds of parse trees.

    Make the augmented compilation unit, which is computed from
    the final module_and_imports structure, likewise switch from
    storing item blocks to storing the whole parse trees of the
    files that went into its construction. With each such parse tree,
    record *why* we read it, since this controls what permissions
    the source module being compiled has for access to the entities
    in the parse tree.

    Simplify the contains_foreign_code type, since one of three
    function symbols was equivalent to one possible use of another
    function symbol.

    Provide a way to record which method of which class a compiler-generated
    predicate is for. (See hlds_pred.m below.)

    Move the code of almost all utility operations to item_util.m
    (which is imported by many fewer modules than prog_item.m),
    keeping just the most "popular" ones.

compiler/item_util.m:
    Move most of the previously-existing utility operations here from
    prog_item.m, most in a pretty heavily modified form.

    Add a whole bunch of other utility operations that are needed
    in more than one other module.

compiler/convert_parse_tree.m:
    Provide predicates to convert from raw compilation units to
    parse_tree_module_srcs, and vice versa (though the reverse
    shouldn't be needed much longer).

    Update the conversion operations between the general parse_tree_int
    and the specific parse_tree_intN forms for the changes in prog_item.m
    mentioned above. In doing so, use a consistent approach, based on
    new operations in item_util.m, to detect errors such as duplicate
    include_module and import/use_module declarations in all kinds
    of parse trees.

    Enforce the invariants that the types of parse trees of various kinds
    can now express in types, generating error messages for their violations.

    Delete some utility operations that have been moved to item_util.m
    because now they are also needed by other modules.

compiler/grab_modules.m:
    Delete code that did tests on raw compilation units that are now done
    when that raw compilation unit is converted to a parse_tree_module_src.
    Use the results of the checks done during that conversion to decide
    which modules are imported/used and in which module section.

    Record a single reason for why we reading in each interface and
    optimization file. The code of make_hlds_separate_items.m will use
    this reason to set up the appropriate permissions for each item
    in those files.

    Use separate code for handling different kinds of interface and
    optimization files. Using generic traversal code was acceptable economy
    when we used the same data structure for every kind of interface file,
    but now that we *can* express different invariants for different kinds
    of interface and optimization file, we want to execute not just different
    code for each kind of file, but the data structures we want to work on
    are also of different types. Using file-kind-specific code is a bit
    longer, but it is significantly simpler and more robust, and it is
    *much* easier to read and understand.

    Delete the code that separates the parts of the implementation section
    that are exported to submodules, and the part that isn't, since that task
    is now done in make_hlds_separate_items.m.

    Pass a database of the files we have read through the relevant predicates.

    Give some predicates more meaningful names.

compiler/notes/interface_files.html:
    Note a problem with the current operation of grab_modules.

compiler/get_dependencies.m:
    Add operations to gather implicit references to builtin modules
    (which have to be made available even without an explicit import_module
    or use_module declaration) in all kinds of parse trees. These have
    more code overall, but will be at runtime, since we need only look at
    the item kinds that may *have* such implicit references.

    Add a mechanism to record the result of these gathering operations
    in import_and_or_use_maps.

    Give some types, function symbols, predicates and variables
    more meaningful names.

compiler/make_hlds_separate_items.m:
    When we stored the contents of the source module and the
    interface and optimization files we read in to augment it
    in the module_and_imports structure as a bunch of item blocks,
    the job of this module was to separate out the different kinds of items
    in the item blocks, returning a single list of each kind of item,
    with each such item being packaged up with its status (which encodes
    a set of permissions saying what the source module is allowed
    to do with it).

    Now that the module_and_imports structure stores this info in
    file-kind-specific parse trees, all of which have separate lists
    for each kind of item and none of which contain item blocks,
    the job of this module has changed. Now its job is to convert
    the reason why each file was read in into the (one or more) statuses
    that apply to the different kinds of items stored in it, wrap up
    each item with its status, and return the resulting overall list
    of status/item pairs for each kind of item.

compiler/read_modules.m:
    Add predicates that, when reading an interface file, return its contents
    in the tightest possible file-kind-specific parse tree.

    Refine the database of files we have read to allow us to store
    more file-kind-specific parse trees.

    Don't require that files in the database have associated timestamps,
    since in some cases, we read files we can put into the database
    *without* getting their timestamps.

    Allow the database to record that an attempt to read a file failed.

compiler/split_parse_tree_src.m:
    Rearchitect how this module separates out nested submodules from within
    the main module in a file.

    Another of the jobs of this module is to generate error messages for
    when module A includes module B twice, whether via nesting or via
    include_module declarations, with one special exception for the case
    where A's interface contains nested submodule A.B's interface,
    and A's implementation contains nested submodule A.B's implementation.
    The problem ironically was that while it reported duplicate include_module
    declarations as errors, split_parse_tree_src.m also *generated*
    duplicate include_module declarations. Since it replaced each nested
    submodule occurrence with an include_module declaration, in the scenario
    above, it generated two include_module declarations for A.B. Even worse,
    the interface incarnation of submodule A.B could contain
    (the interface of) its own nested submodule A.B.C, while its
    implementation incarnation could contain (the implementation section of)
    A.B.C. Each occurrence of A.B.C would be its only occurrence in the
    including part of its parent A.B, which means local tests for duplicates
    do not work. (I found this out the hard way.)

    The solution we now adopt adds include_module declarations to the
    parents of any submodule only once the parse tree of the entire
    file has been processed, since only then do we know all the
    includer/included relationships among nested modules. Until then,
    we just record such relationships in a database as we discover them,
    reporting duplicates when needed (e.g. when A includes B twice
    *in the same section*), but not reporting duplicates when not needed
    (e.g. when A.B includes A.B.C in *different* sections).

compiler/prog_data.m:
    Add a new type, pf_sym_name_and_arity, that exactly specifies
    a predicate or function. It is a clone of the existing simple_call_id
    type, but its name does NOT imply that the predicate or function
    is being called.

    Add XXXs that call for some other improvements in type names.

compiler/prog_data_foreign.m:
    Give a type, and the operations on that type, a more specific name.

compiler/error_util.m:
    Add an id field to all error_specs, which by convention should be
    filled in with $pred. Print out the value in this field if the compiler
    is invoked with the developer-only option --print-error-spec-id.
    This allows a person debugging the compiler find out where in the code
    an undesired error message is coming from significantly easier
    than was previously possible.

    Most of the modules that have changes only "to conform to the changes
    above" will be for this change. In many cases, the updated code
    will also simplify the creation of the affected error_specs.

    Fix a bug that looked for a phase in only one kind of error_spec.

    Add some utility operations needed by other parts of this change.

    Delete a previously internal function that has been moved to
    mdbcomp/prim_data.m to make it accessible in other modules as well.

compiler/Mercury.options:
    Ask the compiler to warn about dead predicates in every module
    touched by this change (at least in one its earlier versions).

compiler/add_foreign_enum.m:
    Replace a check for an inappropriately placed foreign_enum declaration
    with a sanity check, since with this diff, the error should be caught
    earlier.

compiler/add_mutable_aux_preds.m:
    Delete a check for an inappropriately placed mutable declaration,
    since with this diff, the error should be caught earlier.

compiler/add_pragma.m:
    Instead of adding pass2 and pass3 pragmas, add decl and impl and
    generated pragmas.

    Delete the tests for generated pragma occurring anywhere except
    .opt files, since those tests are now done earlier.

    Shorten some too-long predicate names.

compiler/comp_unit_interface.m:
    Operate on as specific kinds of parse trees as the interface of this
    module will allow. (We could operate on more specific parse trees
    if we changed the interface, but that is future work).

    Use the same predicates for handling duplicate include_module,
    import_module and use_module declarations as everywhere else.

    Delete the code of an experiment that shouldn't be needed anymore.

compiler/equiv_type.m:
    Replace code that operated on item blocks with code that operates
    on various kinds of parse trees.

    Move a giant block of comments to the front, where it belongs.

compiler/hlds_module.m:
    Add a field to the module_info that lets us avoid generating
    misleading error messages above missing definitions of predicates
    or functions when those definitions were present but were not
    added to the HLDS because they had errors.

    Give a field and its access predicates a more specific name.

    Mark a spot where an existing type cannot express everything
    it is supposed to.

compiler/hlds_pred.m:
    For predicates which the compiler creates to represent a class method
    (the virtual function, in OOP terms), record not just this fact,
    but the id of the class and of the method. Using this extra info
    in progress messages (with mmc -V) prevents the compiler from printing e.g.

        % Checking typeclass constraints on class method
        % Checking typeclass constraints on class method
        % Checking typeclass constraints on class method

    when checking three such predicates.

compiler/make.m:
    Provide a slot in the make_info structure to allow the database
    of the files we have read in to be passed around.

compiler/make_hlds_error.m:
    Delete predicates that are needed in just one other module,
    and have therefore been moved there.

compiler/make_hlds_passes.m:
    Add decl, impl and generated pragma separately, instead of adding
    pass2 and pass3 pragmas separately.

    Do not generate error messages for clauses, initialises or finalises
    in module interfaces, since with this diff, such errors should be
    caught earlier.

compiler/mercury_compile_main.m:
compiler/recompilation.check.m:
    Explicitly pass around the expanded database of parse trees
    of files that have been read in.

compiler/module_qual.collect_mq_info.m:
compiler/module_qual.m:
compiler/module_qual.qualify_items.m:
    Collect module qualification information, and do module qualification
    respectively on parse trees of various kinds, not item blocks.
    Take information about what the module may do with the contents
    of each interface or optimization file from the record of why
    we read that file, not from the section markers in item blocks.

    Break up some too-large predicates by carving smaller ones out of them.

compiler/options.m:
    Add an option to control whether errors and/or warnings detecting
    when deciding what should go into a .intN file be printed,
    thus (potentially) preventing the creation of that file.

    Add commented-out documentation for a previously totally undocumented
    option.

doc/user_guide.texi:
    Document the new option.

NEWS:
    Announce the new option.

    Mention that we now generate warnings for unused import_module and
    use_module declarations in the interface even if the module has
    submodules.

compiler/write_module_interface_files.m:
    Let the new option control whether we filter out any messages generated
    when deciding what should go into a .intN file.

compiler/parse_item.m:
    Delete actually_read_module_opt, since it is no longer needed;
    its callers now call actually_read_module_{plain,trans}_opt instead.

    Delete unneeded arguments from some predicates.

compiler/parse_module.m:
    Delete some long unused predicates.

compiler/parse_pragma.m:
    When parsing pragmas, wrap them up in the new decl, impl or generated
    pragma kinds.

compiler/parse_tree_out.m:
    Add predicates to write out each of the file-kind-specific parse trees.

compiler/parse_tree_out_pragma.m:
    Add predicates to write out decl, impl and generated pragmas.

compiler/polymorphism.m:
    Add a conditionally-enabled progress message, which can be useful
    in tracking down problems.

compiler/prog_item_stats.m:
    Conform NOT to the changes above beyond what is needed to let this module
    compile. Let that work be done the next time the functionality of
    this module is needed, by which time the affected data structures
    maybe have changed further.

compiler/typecheck.m:
    Fix a performance problem. With intermodule optimization, we read in
    .opt files, some of which (e.g. list.opt and int.opt) contain promises.
    These promises are read in as predicates with goal_type_promise,
    but they do not have declarations of the types of their arguments
    (since promises do not have declarations as such). Those argument types
    therefore have to be inferred. That inference replaces the original
    "I don't know" argument types with their actual types.

    The performance problem is that when we change the recorded argument types
    of a predicate, we require another loop over all the predicates in the
    module, so that any calls to this predicate can be checked against
    the updated types. This is as it should be for callable predicates,
    but promises are not callable. So if all the *only* predicates whose
    recorded argument types change during the first iteration to fixpoint
    are promises, then a second iteration is not needed, yet we used to do it.

    The fix is to replace the "Have the recorded types of this predicate
    changed?" boolean flag with a bespoke enum that says "Did the checking
    of this predicate discover a need for another iteration", and not
    setting it when processing predicates whose type is goal_type_promise.

compiler/typecheck_errors.m:
    Do not generate an error message for a predicate missing its clauses
    is the clauses existed but were not added to the HLDS because they were
    in the interface section.

    When reporting on ambiguities (when a call can match more than one
    predicate or function), sort the possible matches before reporting
    them.

compiler/accumulator.m:
compiler/add_class.m:
compiler/add_clause.m:
compiler/add_foreign_proc.m:
compiler/add_mode.m:
compiler/add_pragma_tabling.m:
compiler/add_pragma_type_spec.m:
compiler/add_pred.m:
compiler/add_type.m:
compiler/canonicalize_interface.m:
compiler/check_for_missing_type_defns.m:
compiler/check_parse_tree_type_defns.m:
compiler/check_promise.m:
compiler/check_raw_comp_unit.m:
compiler/check_typeclass.m:
compiler/common.m:
compiler/compile_target_code.m:
compiler/compiler_util.m:
compiler/dead_proc_elim.m:
compiler/deps_map.m:
compiler/det_analysis.m:
compiler/det_report.m:
compiler/du_type_layout.m:
compiler/field_access.m:
compiler/find_module.m:
compiler/float_regs.m:
compiler/format_call.m:
compiler/goal_expr_to_goal.m:
compiler/handle_options.m:
compiler/hlds_out_module.m:
compiler/hlds_out_pred.m:
compiler/hlds_out_util.m:
compiler/inst_check.m:
compiler/intermod.m:
compiler/introduce_parallelism.m:
compiler/layout_out.m:
compiler/make.dependencies.m:
compiler/make.module_dep_file.m:
compiler/make_hlds_warn.m:
compiler/mark_tail_calls.m:
compiler/mercury_compile_llds_back_end.m:
compiler/ml_top_gen.m:
compiler/mmakefiles.m:
compiler/mode_errors.m:
compiler/mode_robdd.equiv_vars.m:
compiler/modes.m:
compiler/module_qual.qual_errors.m:
compiler/oisu_check.m:
compiler/old_type_constraints.m:
compiler/options_file.m:
compiler/parse_class.m:
compiler/parse_dcg_goal.m:
compiler/parse_goal.m:
compiler/parse_inst_mode_defn.m:
compiler/parse_inst_mode_name.m:
compiler/parse_mutable.m:
compiler/parse_sym_name.m:
compiler/parse_type_defn.m:
compiler/parse_type_name.m:
compiler/parse_type_repn.m:
compiler/parse_types.m:
compiler/parse_util.m:
compiler/parse_vars.m:
compiler/post_term_analysis.m:
compiler/post_typecheck.m:
compiler/prog_event.m:
compiler/prog_mode.m:
compiler/purity.m:
compiler/qual_info.m:
compiler/recompilation.version.m:
compiler/resolve_unify_functor.m:
compiler/simplify_goal.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_disj.m:
compiler/simplify_goal_ite.m:
compiler/simplify_proc.m:
compiler/state_var.m:
compiler/stratify.m:
compiler/style_checks.m:
compiler/superhomogeneous.m:
compiler/table_gen.m:
compiler/term_constr_errors.m:
compiler/term_errors.m:
compiler/termination.m:
compiler/trace_params.m:
compiler/unused_args.m:
compiler/unused_imports.m:
compiler/write_deps_file.m:
compiler/xml_documentation.m:
    Conform to the changes above.

mdbcomp/prim_data.m:
    Move a utility function on pred_or_funcs here from a compiler module,
    to make it available to other compiler modules as well.

scripts/compare_s1s2_lib:
    A new script that helped debug this diff, and may help debug
    similar diffs the future. It can compare (a) .int* files, (b) .*opt
    files, (c) .mh/.mih files or (d) .c files between the stage 1 and
    stage 2 library directories. The reason for the restriction
    to the library directory is that any problems affecting the
    generation of any of these kinds of files are likely to manifest
    themselves in the library directory, and if they do, the bootcheck
    won't go on to compile any of the other stage 2 directories.

tests/debugger/breakpoints.a.m:
tests/debugger/breakpoints.b.m:
    Move import_module declarations to the implementation section
    when they are not used in the interface. Until now, the compiler
    has ignored this, but this diff causes the compiler to generate
    a warning for such misplaced import_module declarations even modules
    that have submodules. The testing of such warnings is not the point
    of the breakpoints test.

tests/invalid/Mercury.options:
    Since the missing_interface_import test case tests error messages
    generated during an invocation of mmc --make-interface, add the
    new option that *allows* that invocation to generate error messages.

tests/invalid/ambiguous_overloading_error.err_exp:
tests/invalid/max_error_line_width.err_exp:
tests/warnings/ambiguous_overloading.exp:
    Expect the updated error messages for ambiguity, in which
    the possible matches are sorted.

tests/invalid/bad_finalise_decl.m:
tests/invalid/bad_initialise_decl.m:
    Fix programming style.

tests/invalid/bad_item_in_interface.err_exp:
    Expect an error message for a foreign_export_enum item in the interface,
    where it should not be.

tests/invalid/errors.err_exp:
    Expect the expanded wording of a warning message.

tests/invalid/foreign_enum_invalid.err_exp:
    Expect a different wording for an error message. It is more "standard"
    but slightly less informative.

tests/invalid_submodules/children2.m:
    Move a badly placed import_module declaration, to avoid having
    the message the compiler now generates for it from affecting the test.

tests/submodules/parent2.m:
    Move a badly placed import_module declaration, to avoid having
    the message the compiler now generates for it from affecting the test.

    Update programming style.
2020-03-13 12:58:33 +11:00
Zoltan Somogyi
6bfef65f50 Fix the reminder about hidden messages itself being hidden.
compiler/mercury_compile_main.m:
    When we generate more messages for the user than we show, either
    because of --limited-error-context options or because the user has
    not asked for the verbose part of messages, we used to print a reminder
    about this fact in only one case:

    - at the end of the compilation, and
    - only if the exit status wasn't zero.

    Both of these condition was wrong.

    - If we were compiling modules a, b, c, d ... z, we could get a message
      about more messages being available being printed after the compilation
      of a module (z) for which we generated *no* messages at all, just because
      some message earlier in the list got such messages.

    - If the compilation generated no errors but only warnings, then
      we never printed reminders about any verbose parts of those warnings
      being held back.

    Fix both of these issues by

    - separating the code doing the reminder into its own predicate,
      and invoking it at the end of the processing of each module
      (leaving a call at its old location where it is invoked
      after we have processed all modules), and

    - not making the invocation conditional on exit status.

tests/warnings/ambiguous_overloading.exp:
tests/warnings/arg_order_rearrangment.exp:
tests/warnings/bug477.exp:
tests/warnings/infinite_recursion.exp:
tests/warnings/simple_code.exp:
tests/warnings/singleton_test.exp:
tests/warnings/singleton_test.exp2:
tests/warnings/singleton_test.exp3:
tests/warnings/singleton_test.exp4:
    Update these to expect the "For more information, recompile with `-E'"
    message, now that we don't hide it.

tests/warnings/singleton_test.m:
    Document what the four .exp files are for.
2019-10-26 13:21:30 +11:00
Zoltan Somogyi
83dc913329 Update the style of the warnings test cases.
tests/warnings/*.m:
    Bring the programming style of these modules up to date,
    except where the problem being tested for seems to be related
    to the old programming style

    In the infinite_recursion test case, add code that we *should*
    warn about, but currently don't.

tests/warnings/*.m:
    Update the expected outputs to account for the changes in line
    numbers, and the fact that the compiler computes the contexts
    of (if C then T else E) if-then-elses differently from (C -> T; E)
    if-then-else (it takes the context of the "then" vs the context
    of the ";").

    Delete arg_order_rearrangment.exp2. It was long unused, but
    deleting it in CVS would not have allowed us to put it back later.
2019-04-20 09:37:37 +10:00
Zoltan Somogyi
fdd141bf77 Clean up the tests in the other test directories.
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.
2015-02-16 12:32:18 +11:00
Zoltan Somogyi
91ce3a67a2 Avoid a compiler abort when people put a period in the middle of a clause.
The abort was caused by the fact that when the parser found an item that
looks like a fact for an undeclared predicate, such as the predicate ','/,
it created a hlds_pred filled with a clause_info in which terms that the
user intended to be goals are instead taken to be terms. Any reference
to predicates in those terms are taken by purity-checking to be higher order
references, which need a mode declaration. If the reference is to a predicate
(such as ,/2) whose declaration is implicit, that mode declaration will be
missing.

The fix has two parts. First, do not generate an abort in purity checking
when finding the mode declaration of a predicate or function in (what seems to
be) a higher order term is missing. Second, do not generate implicit
declarations for ,/2, since this is NEVER what the user wants.

A third part of this diff is an improvement in the contexts we record
for terms, for better error messages. I noticed the need for this when
looking at the compiler's output for the new cases.

compiler/post_typecheck.m:
   When finding an apparent reference to a predicate or function with
   no mode declarations, do not abort; instead, report an error.

compiler/purity.m:
   Record the error reported by post_typecheck.m.

compiler/add_clause.m:
   If we see a clause for `,'/2, do NOT treat it as implicitly defining
   a ,/2 predicate. Instead, generate a situation-specific error message that
   mentions the usual cause of the error.

compiler/add_pred.m:
   Clean up the predicates that add the implicit predicate declarations
   by making them both update module_infos, and by putting their arguments
   into a consistent order.

compiler/make_hlds_passes.m:
   Do likewise for a couple of predicates here.

compiler/add_pragma.m:
   Conform to the change to add_pred.m.

compiler/superhomogeneous.m:
   When expanding a term such as

      line 1: p(a,
      line 2: p(b,
      line 3: c))

   associate line 2 with the unification of a fresh variable with b,
   and line 3 with the unification of a fresh variable with c. We used
   to use the context of the top level term, which in this case is line 1,
   instead.

   This makes the compiler generate better (less misleading) output for the
   ref_to_implicit_pred.m test case below, as well as in many other cases.

compiler/state_var.m:
   When replacing !.X or !:X with a fresh variable term, copy the context
   of the original functor term to the new variable term. Before the change
   to superhomogeneous.m, this wasn't needed since the context of that term
   was ignored, but now we use it.

tests/invalid/ref_to_implicit_pred.{m,err_exp}:
   New test case to test the first part of the fix.

tests/invalid/ref_to_implicit_comma.{m,err_exp}:
   New test case to test the second part of the fix.

tests/invalid/Mmakefile:
   Enable both new test cases.

tests/hard_coded/impl_def_literal.{m,exp}:
   Update this expected output for the more accurate contexts we now
   generate, and update the comment in the source code accordingly.

tests/invalid/ambiguous_overloading_error.exp:
tests/invalid/max_error_line_width.err_exp:
tests/invalid/transitive_import_class.err_exp:
tests/warnings/ambiguous_overloading.exp:
   Update these expected outputs for the more accurate contexts we now
   generate.
2014-04-17 23:14:49 +10:00
Zoltan Somogyi
b72243cadf Lookups in the map from type_ctors to their definitions are relatively
Estimated hours taken: 6
Branches: main

Lookups in the map from type_ctors to their definitions are relatively
expensive, due to the cost of repeatedly comparing type_ctors, comparisons
that are relatively expensive. This diff replaces that direct map
with a two-stage map, the first stage being a map on the type constructor name
(a plain string), and the second stage being a map of the full type_ctor.
Most of the job of searching is done by the first map, since the second map
can be expected to have only one entry most of the time.

An earlier diff yielded a reduction of 1.1% in compilation time, as measured
by a version of tools/speedtest which compiles six modules in grade hlc.gc.
The speedup when compiling in grade asm_fast.gc was 0.6%. (The MLDS code
generator does more lookups of type definitions than the LLDS code generator.)
This diff also has some more changes that led to some further speedups, but
I don't have the original basis for comparison anymore.

Note that making the type table's type abstract leads to a slowdown,
but the faster data structure more than compensates for it.

compiler/hlds_data.m:
	Make the type table an abstract type, and change its representation
	as described above. Provide the operations on it that are needed
	by the other modules of the compiler.

compiler/*.m:
	Use the operations provided by hlds_data.m instead of operations on
	maps to access the type table.

	In several cases replace old code that iterated on keys and looked up
	the associated values in the map, with new code that iterates on an
	association list that puts the value right next to its key (a list
	that the old code just threw away).

	In other cases, change code that iterated on a list of the keys
	to iterating on the whole assoc_list instead, paying attention only
	to the keys. This is faster, since it avoids allocating memory
	for the list of keys.

compiler/type_ctor_info.m:
	This module used to use a roundabout method of generating
	type_ctor_gen_infos for the builtin types conceptually defined
	in builtin.m. It used to add their type_ctors to the list of
	user-defined type_ctors it processed, and the code that processed
	each type_ctor would check whether it was one of these, and if yes,
	handle them specially.

	This diff makes the code handle these builtin type_ctors and
	user-defined type_ctors separately, avoiding a whole bunch of tests.

compiler/typecheck_errors.m:
	Sort lists of types shown in error messages. The new data type table
	would naturally lead to slightly different orders of types in error
	messages than the old one; this change neutralizes such effects
	for the future.

tests/invalid/ambiguous_overloading.err_exp:
tests/invalid/errors2.err_exp:
tests/warnings/ambiguous_overloading.exp:
	Expect sorted types in error messages.
2009-09-04 02:28:10 +00:00
Peter Wang
33f4685203 Change some data representations to avoid repeatedly appending lists when
Branches: main

Change some data representations to avoid repeatedly appending lists when
reading optimisation interface files and calculating dependencies.

compiler/module_imports.m:
	Change `module_imports' to hold items in a cord instead of a list.

	Add getter/setter for items that work with lists, as most code will
	continue to use lists.

	Make `get_dependencies' and `get_dependencies_int_imp' accumulate
	sets of modules instead of lists.

compiler/intermod.m:
	Conform to `module_imports' changes.

	Make `read_optimization_interfaces' accumulate cords of items
	so that appending a list of items doesn't rebuild as big a list.

compiler/make.module_dep_file.m:
compiler/mercury_compile.m:
compiler/modules.m:
compiler/trans_opt.m:
compiler/write_deps_file.m:
	Conform to `module_imports' changes.

tests/invalid/ambiguous_overloading_error.err_exp:
tests/warnings/ambiguous_overloading.exp:
	Update expected outputs, which were changed due to the
	`get_dependencies' change.
2008-09-05 03:57:38 +00:00
Zoltan Somogyi
a23873984b In the presence of large amounts of unresolved overloading, the compiler could
Estimated hours taken: 6
Branches: main

In the presence of large amounts of unresolved overloading, the compiler could
consume unbounded amounts of space and time. This diff fixes this problem.

I tried to avoid having this fix lead to a slowdown; in fact, the last three
changes to typecheck_info.m lead to a slight speedup.

compiler/options.m:
doc/user_guide.texi:
	Add a new option, --typecheck-ambiguity-error-limit. This gives the
	number of type assignments that cause the typechecker to stop
	processing further goals. No such facility existed before.

	Add a new option, --typecheck-ambiguity-warn-limit. This gives the
	number of type assignments that cause the typechecker to emit a
	warning. This generalizes the previous hard-coded value in typecheck.m.

	Move the definitions of some existing options to the right set of
	options.

compiler/typecheck_info.m:
	Add the values of the two new options as fields to the typecheck_info,
	since we will want to look them up often.

	Separate out the error_specs concerned with overloading from the other
	error specs, since we want to be able to have an error about excessive
	overloading to overwrite a warning about excessive overloading
	generated earlier.

	Fix a performance bug: the pred_markers were being looked up in the
	pred_info each time they were asked for, even though they were also
	available directly in a field.

	Move the least frequently accessed fields of the typecheck_info
	into a separate substructure, to reduce amount of allocation required.

	Delete the get and set predicates for the most frequently used fields,
	to avoid the overhead of cross-module calls. These fields are now
	accessed via field access functions.

compiler/typecheck.m:
	Don't typecheck goals if the number of type assignments exceeds
	the error limit.

	Conform to the changes in typecheck_info.m.

compiler/typecheck_errors.m:
	Add a function to generate the new error message.

	Conform to the changes in typecheck_info.m.

tests/invalid/ambiguous_overloading_error.{m,err_exp}:
	Add this new test case. It is a copy of the existing test case
	warnings/ambiguous_overloading, but with more overloading. Old
	compilers consume so much memory on it that they eventually run out
	and crash, but the new compiler generates an error message
	and finishes quickly.

tests/invalid/Mmakefile:
	Enable the new test case.

tests/warnings/ambiguous_overloading.exp:
	Update the output of this test case to account for the fact that
	the context of the warning is now that of the goal *after* the point
	at which the number of type assignments exceeds 50, not the goal
	*before* this point.
2007-05-14 08:20:17 +00:00
Zoltan Somogyi
5eee81204e A big step towards cleaning up the way we handle errors.
Estimated hours taken: 28
Branches: main

A big step towards cleaning up the way we handle errors. The main changes are

- the provision, in error_util.m, of a mechanism for completely specifying
  everything to do with a single error in one data structure,

- the conversion of typecheck_errors.m from using io.write_string to
  using this new capability,

- the conversion of mode_errors.m and det_report.m from using
  write_error_pieces to using this new capability, and

- consistently using the quoting style `symname'/N instead of `symname/N'
  in error_util and hlds_error_util (previously, error_util used the former
  but hlds_error_util used the latter).

This diff sets up later diffs which will collect all error specifications
in a central place and print them all at once, in order.

compiler/error_util.m:
	The new type error_spec, which completely specifies an error.
	An error_spec may have multiple components with different contexts
	and may have parts which are printed only under certain conditions,
	e.g. a given option being set. Each error_spec has a severity
	and also records which phase found the error.

	The new predicate write_error_spec takes care of updates of the exit
	status for errors and (if --halt-at-warn is set) for warnings. It also
	takes care of setting the flag that calls for the reminder about -E
	at the end.

	This diff also makes it simpler to use the ability to print arbitrary
	output. It adds the ability to include integers in messages directly,
	and the ability to create blank lines. It renames some function symbols
	to avoid ambiguities.

	Move a predicate that only used by typecheck_errors.m to that file.

compiler/hlds_error_util.m:
	Switch to the `symname'/N quoting style for describing predicates and
	procedures.

compiler/prog_util.m:
	Switch to the `symname'/N quoting style for describing
	sym_name_and_arity.

compiler/hlds_module.m:
	Provide a predicate to increment the number of errors not by one,
	but by the number of errors printed by write_error_spec.

	Fix some documentation rot.

compiler/typecheck_errors.m:
	Use write_error_spec instead of io.write_strings to print error
	messages. In several cases, improve the formatting of the messages
	printed.

	Mark a number of places where we don't (yet) update the number of
	errors in the module_info correctly.

	Rename the checkpoint predicate to avoid potential ambiguity with
	similar predicates in e.g. mode_info.

compiler/typecheck_info.m:
	Group the code for writing stuff out together in one bunch. For each
	such predicate, create another that returns a list of format components
	instead of doing I/O directly.

compiler/typecheck.m:
	Move the code for writing inference messages here from
	typecheck_errors.m, since these messages aren't errors.

compiler/mode_errors.m:
compiler/det_report.m:
	Use write_error_spec instead of write_error_pieces. In the case of
	mode_errors.m, this means we now get correct the set of circumstances
	in which we set the flag that calls for the reminder about -E.

compiler/add_pragma.m:
compiler/add_type.m:
	Convert some code that used to use write_error_pieces to print error
	messages to use write_error_spec instead.

compiler/assertion.m:
compiler/hlds_pred.m:
compiler/post_typecheck.m:
	Assertion.m used to contain some code to check for assertions in the
	interface that mention predicates that are not exported. Move most
	of this code to post_typecheck.m (which is where this code used to be
	called from). One small part, which is a test for a particular property
	of import_statuses, is moved to hlds_pred.m to be with all the other
	similar tests of import_statuses.

compiler/prog_util.m:
	Change unqualify_name from a predicate to a function.

compiler/pred_table.m:
compiler/hlds_out.m:
	Avoid some ambiguities by adding a suffix to the names of some
	predicates.

compiler/*.m:
	Conform to the changes above.

library/list.m:
	Add a function that was previously present (with different names)
	in two compiler modules.

tests/hard_coded/allow_stubs.exp:
	Update the format of the expected exception.

tests/invalid/errors2.err_exp2:
	Remove this file. As far as I can tell, it was never the correct
	expected output on the main branch. (It originated on the alias branch
	way back in the mists of time.)

tests/invalid/*.err_exp:
tests/invalid/purity/*.err_exp:
tests/warnings/*.exp:
	Update the format of the expected error messages.

tests/recompilation/*.err_exp.2:
	Update the format of the expected messages about what was modified.
2006-09-07 05:51:48 +00:00
Zoltan Somogyi
114ed9d8c5 Fix a performance problem in the handling of highly overloaded code.
Estimated hours taken: 2
Branches: main

Fix a performance problem in the handling of highly overloaded code.

compiler/typecheck_info.m:
	We used to record ambiguous overloading situations in a set of
	context/info pairs. Since sets are represented as sorted lists,
	adding N new situation's records had complexity O(n^2). If N is large,
	that can be too slow. (N can be large without causing typecheck.m to
	abort if there are lots of disjuncts, each with a tolerable amount
	of ambiguity.) From now on, we represent these situations as a map
	from overloaded symbols to the unsorted list of of contexts in which
	that symbol is used. Since we can add new contexts to the front,
	the complexity of the new algorithm is just O(log N), with an
	O(n log n) sort at the end.

compiler/typecheck.m:
	Use the interface in typecheck_info to record ambiguities.

compiler/typecheck_errors.m:
	Use the new format to improve the error messages for ambiguous code:
	give the list of possible matches for each ambiguous symbol just once.

tests/warnings/ambiguous_overloading.exp:
	Update this expected output file for the now non-redundant error
	messages.
2006-07-31 03:19:29 +00:00
Zoltan Somogyi
46a67b0b48 When the typechecker finds highly ambiguous overloading, print what symbols
Estimated hours taken: 16
Branches: main

When the typechecker finds highly ambiguous overloading, print what symbols
were overloaded, and where they occurred. Without this information, it is
very hard to fix the error if the predicate body is at all large.

Fix some software engineering problems encountered during this process.
Modify some predicates in error_util in order to simplify their typical usage.
Change the type_ctor type to be not simply a sym_name - int pair but a type
with its own identifying type constructor. Change several other types that
were also sym_name - int pairs (mode_id, inst_id, item_name, module_qual.id
and the related simple_call_id) to have their own function symbols too.

compiler/typecheck_info.m:
	Add a field to the typecheck_info structure that records the overloaded
	symbols encountered.

compiler/typecheck.m:
	When processing ambiguous predicate and function symbols, record this
	fact in the typecheck_info.

	Add a field to the cons_type_info structure to make this possible.

compiler/typecheck_errors.m:
	When printing the message about highly ambiguous overloading,
	what the overloaded symbols were and where they occurred.

compiler/error_util.m:
	Make error_msg_specs usable with plain in and out modes by separating
	out the capability requiring special modes (storing a higher order
	value in a function symbol) into its own, rarely used type.

	Make component_list_to_line_pieces a bit more flexible.

compiler/prog_data.m:
compiler/module_qual.m:
compiler/recompilation.m:
	Change the types listed above from being equivalence types (pairs)
	to being proper discriminated union types.

compiler/*.m:
	Conform to the changes above.

	In some cases, simplify the code's use of error_util.

tests/warnings/ambiguous_overloading.{m,exp}:
	Greatly extend this test case to test the new functionality.

tests/recompilation/*.err_exp.2
	Reflect the fact that the expected messages now use the standard
	error_util way of quoting sym_name/arity pairs.
2006-04-20 05:37:13 +00:00
Zoltan Somogyi
bc56e927b6 Detect when a predicate has a pair of I/O states but isn't det or cc_multi.
Estimated hours taken: 6
Branches: main

Detect when a predicate has a pair of I/O states but isn't det or cc_multi.
Improve the generation of determinism error messages.

compiler/det_analysis.m:
	Detect when a predicate has a pair of I/O states but isn't det or
	cc_multi.

	Factor out some common code.

compiler/det_report.m:
	Add the new error type for predicates with I/O states.

	Use error_util much more extensively to generate error messages.

compiler/hlds_out.m:
	For several existing predicates that write out various HLDS
	constructs, provide versions that return representations of those
	constructs as strings or as error_util pieces, for use by det_report.m.
	Redefine the old predicates as simply printing the output of the new
	predicates where relevant, to avoid code duplication.

compiler/error_util.m:
	When describing a predicate name, specify whether we want to module
	qualify the name or not. The intention is that when generating a kind
	of error message which can only be generated for predicates defined
	in the current module, the module prefix should be omitted in the
	interest of clarity.

compiler/accumulator.m:
compiler/dead_proc_elim.m:
compiler/magic_util.m:
compiler/table_gen.m:
compiler/term_errors.m:
compiler/termination.m:
compiler/typecheck.m:
	Conform to the changes in error_util.m.

compiler/globals.m:
	Reorder arguments to allow the use of state variable notation.

compiler/handle_globals.m:
compiler/mercury_compile.m:
compiler/source_file_map.m:
	Conform to the changed argument order in globals.m.

tests/invalid/aditi_update_errors.err_exp:
tests/invalid/errors2.err_exp2:
tests/invalid/external.err_exp:
tests/invalid/ho_unique_error.err_exp:
tests/invalid/magicbox.err_exp:
tests/invalid/missing_det_decls.err_exp:
tests/invalid/mostly_uniq1.err_exp:
tests/invalid/mostly_uniq2.err_exp:
tests/invalid/multimode_syntax.err_exp:
tests/invalid/multisoln_func.err_exp:
tests/invalid/pragma_c_code_dup_var.err_exp:
tests/invalid/pragma_c_code_no_det.err_exp:
tests/invalid/prog_io_erroneous.err_exp2:
tests/invalid/qualified_cons_id2.err_exp:
tests/invalid/record_syntax_errors.err_exp:
tests/invalid/state_vars_test1.err_exp:
tests/invalid/state_vars_test2.err_exp:
tests/invalid/state_vars_test3.err_exp:
tests/invalid/typeclass_mode.err_exp:
tests/invalid/types.err_exp2:
tests/invalid/undef_mode_and_no_clauses.err_exp:
tests/recompilation/typeclass_method_pragma_r.err_exp.2:
tests/warnings/ambiguous_overloading.exp:
tests/warnings/duplicate_call.exp:
tests/warnings/duplicate_const.exp:
tests/warnings/infinite_recursion.exp:
tests/warnings/simple_code.exp:
tests/warnings/warn_dead_procs.exp:
tests/warnings/warn_stubs.exp:
	Update these files to expect the better error messages we now generate.
2004-05-14 08:40:33 +00:00
Ralph Becket
a8ffd3680c Change the compiler and tools so that .' and not :' is now used as the
Estimated hours taken: 14
Branches: main

Change the compiler and tools so that `.' and not `:' is now used as the
module separator in all output.

Infix `.' now has associativity yfx and priority 10.

NEWS:
	Report the change.

configure.in:
	Amend the test for an up-to-date Mercury compiler to check whether
	it recognises `.' as a module qualifier.

compiler/code_gen.m:
compiler/error_util.m:
compiler/hlds_out.m:
compiler/prog_out.m:
compiler/prog_util.m:
compiler/rl_exprn.m:
compiler/rl_gen.m:
compiler/source_file_map.m:
compiler/unused_args.m:
library/io.m:
library/rtti_implementation.m:
library/type_desc.m:
runtime/mercury_debug.c:
runtime/mercury_deconstruct.c:
runtime/mercury_stack_trace.c:
	Change `:' to `.' as module separator for output.

compiler/mercury_to_mercury.m:
compiler/prog_io_typeclass.m:
	As above.
	Fixed a bug where `.' was not being recognised as a module separator.

doc/reference_manual.texi:
	Report the change.

library/term_io.m:
	Ensure that infix `.' is written without surrounding spaces.

tests/hard_coded/dot_separator.m:
tests/hard_coded/dot_separator.exp:
tests/hard_coded/Mmakefile:
	Test case added.
2003-01-17 05:57:20 +00:00
Fergus Henderson
1641ea26ef Fix a bug: rejj's changes to the error messages had
Estimated hours taken: 0.5

compiler/typecheck.m:
	Fix a bug: rejj's changes to the error messages had
	broken the formatting of the "highly ambiguous overloading"
	warning.

tests/warnings/Mmakefile:
tests/warnings/ambiguous_overloading.m:
tests/warnings/ambiguous_overloading.exp:
	Regression test.
2000-04-19 07:26:31 +00:00