Files
mercury/tests/invalid/require_complete_nested_switch.m
Zoltan Somogyi f345d20e33 Rename X's aux modules as X_helper_N in invalid.
tests/invalid/*.m:
    Rename modules as mentioned above.

    In two cases where the main module name is a Mercury keyword (to the
    extent that Mercury has keywords), add a "test_" prefix to the
    module name.

    Reorganize the ho_default_func_2 test case. The original code
    of this test had three modules, a parent and two children,
    with the module being tested being one of the *child* modules
    (ho_default_func_2.sub). This does not work; the .log file
    from the successful execution of this test case showed that
    there was no actual compilation involved; the test stopped
    after invoking "mmc --generate-dependencies" on that child module.
    The new version of this test makes that child module the main module,
    and moves the relevant parts of the other two original modules
    into a single new child module.

    Rename ii_parent to instance_pc (pc being short for parent-child).
    This test case still has the child module listed as the target
    in Mmakefile, so it still does not progress past generating its
    dependencies.

    Rename the imported_mode test case as bad_exported_mode,
    because this is what it was testing.

    exported_mode.m was used both as the main module of a test,
    and as a helper module in the imported_mode test (now renamed
    to bad_exported_mode). Make a copy of it as a helper module
    for bad_exported_mode.

    Update all references to the moved modules.

    General updates to programming style, such as

    - replacing DCG notation with state var notation
    - adding lines around vim modelines
    - fixing indentation
    - fixing grammar errors in comments

tests/hard_coded/Mmakefile:
tests/hard_coded/Mercury.options:
    Update all references to the moved modules and/or moved lines.
2023-06-16 20:18:36 +02:00

113 lines
3.8 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
%
% This is a regression test. Versions of the compiler before 2023 april 19
% generated a quite misleading error message for the bug in test_pred.
%
% The bug is that the switch on Str has an arm that is explicitly for
% "Str = k", but this test is *also* present in the first switch arm,
% which is now for a, b and k. This can come about naturally when
%
% - k used to be treated the same way as a and b;
% - the programmer decides to give k its own switch arm, but
% - then forgets to delete the "Str = k" from its original switch arm.
%
% (That is exactly what happened with the original code that inspired
% this cut-down test case.)
%
% The original version of the compiler generated two errors for this bug:
%
% Warning: this disjunct will never have any solutions.
% Error: the goal inside the require_complete_switch [Str] scope is
% not a switch on `Str'.
%
% The contexts were the position of the first Str = k in the code
% (the line marked below as THE PROBLEM LINE), and the position of the
% first require_complete_switch scope respectively. These are confusing
% because
%
% - there is not supposed to be a disjunct at THE PROBLEM LINE, since
% switch detection is supposed to transform that disjunct into a switch arm,
% and
% - the body of the require_complete_switch [Str] scope IS in fact a switch
% on Str.
%
% The reason why these error messages are misleading is that despite
% the contexts, they do not refer to that piece of code at all. They refer
% to a *copy* of that code. When switch detection sees that there are
% *two* switch arms for Str = k, it creates a separate arm of the switch
% on Str for the Str = k case, and sets the code of this arm to be
% a two-way disjunction containing the code that came after the two
% occurrences of Str = k. This meant that the second disjunct was
% "Msg = arg_k", and the first disjunct was this:
%
% BaseMsg = "arm_ab_",
% require_complete_switch [Str]
% (
% Str = "a",
% Msg = BaseMsg ++ "arm_a"
% ;
% Str = "b",
% Msg = BaseMsg ++ "arm_b"
% )
%
% The compiler recognized that *none* of those two switch arms of this *inner*
% switch is actually reachable in the Str = k branch of the *outer* switch
% on Str, so it replaced this switch with fail, which meant that this disjunct
% couldn't succeed (hence the first error message). The fact that it replaced
% the switch with fail but kept the require_complete_switch scope led to the
% second error message.
%
% So both the error messages the compiler generates are justified, including
% the line numbers attached to them. What made them misleading was the lack
% of any reference to the fact that the error occurs only inside the Str = k
% arm of the outer switch. The fix for that is to print this context.
:- module require_complete_nested_switch.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module list.
:- import_module string.
main(!IO) :-
( if test_pred("abc", Msg) then
io.format("Success: %s\n", [s(Msg)], !IO)
else
io.format("Failure\n", [], !IO)
).
:- pred test_pred(string::in, string::out) is semidet.
test_pred(Str, Msg) :-
(
( Str = "a"
; Str = "b"
; Str = "k" % THE PROBLEM LINE
),
BaseMsg = "arm_ab_",
require_complete_switch [Str]
(
Str = "a",
Msg = BaseMsg ++ "arm_a"
;
Str = "b",
Msg = BaseMsg ++ "arm_b"
)
;
Str = "k",
Msg = "arg_k"
;
( Str = "x"
; Str = "y"
),
Msg = "arg_x_y"
).