Files
mercury/compiler/parse_vars.m
Zoltan Somogyi 1da267e9f0 Fix a bug in handling instances with --warn-unused-imports.
This fixes Mantis bug #412.

compiler/unused_imports.m:
    Consider that an instance declaration makes a module "used" only if
    it occurs in the module being compiled, not in an imported or ancestor
    module. (Mantis bug 412 was caused by instance declarations in implicitly
    imported modules.)

    Fixing #412 also exposed another bug. When computing the set of modules
    used by predicates, we considered (besides some non-type entities)
    only the types of the predicate's arguments, not the types of non-argument
    variables. In one case in the compiler (mmc_analysis.m), this lead to
    some actually-used modules not being marked as such, which lead to
    false unused-import warnings to be generated for them. Fix this by scanning
    the types of all variables in all of a predicate's procedures, not just
    the arguments.

    Improve the infrastructure for debugging similar problems.

    Note some possibilities for future improvement.

    Change a predicate name to fit the naming scheme.

compiler/analysis.m:
    Add an XXX about a possible improvement.

compiler/hlds_out_module.m:
    Make the output we generate for instance methods more readable.
    As part of this, fix an old bug in the printing of the instance table:
    the first line of the first method of each concrete instance declaration
    was accidentally commented out.

compiler/parse_tree_out.m:
    Export a different utility predicate for hlds_out_module.m. Make its name
    conform to the scheme used by related predicates.

browser/browse.m:
compiler/add_mutable_aux_preds.m:
compiler/add_pred.m:
compiler/add_special_pred.m:
compiler/check_for_missing_type_defns.m:
compiler/check_promise.m:
compiler/exception_analysis.m:
compiler/handle_options.m:
compiler/inst_match.m:
compiler/mercury_to_mercury.m:
compiler/ml_tailcall.m:
compiler/module_qual.m:
compiler/op_mode.m:
compiler/parse_inst_mode_defn.m:
compiler/parse_tree_out_clause.m:
compiler/parse_tree_out_info.m:
compiler/parse_tree_out_inst.m:
compiler/parse_tree_out_pragma.m:
compiler/parse_tree_out_pred_decl.m:
compiler/parse_tree_out_term.m:
compiler/parse_type_defn.m:
compiler/parse_type_name.m:
compiler/parse_util.m:
compiler/parse_vars.m:
compiler/prog_ctgc.m:
compiler/recompilation.usage.m:
compiler/resolve_unify_functor.m:
compiler/term_constr_main.m:
compiler/term_constr_main_types.m:
compiler/write_deps_file.m:
library/bt_array.m:
    Delete unused imports.

compiler/module_qual.qual_errors.m:
    Import a module that the parent module_qual.m doesn't import anymore.

tests/warnings/bug412.{m,exp}:
    The test case for this bug.

tests/warnings/Mmakefile:
tests/warnings/Mercury.options:
    Enable the new test case.

tests/invalid/import_in_parent.err_exp:
    Update the expected output for this test case. The parent module
    does not use the imported module (bool) at all, so this is what the
    error message says after this diff, though its submodule does use bool.
2016-07-17 10:20:29 +02:00

362 lines
14 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2016 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% This module defines predicates that parse lists of variables.
%
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- module parse_tree.parse_vars.
:- interface.
:- import_module parse_tree.error_util.
:- import_module parse_tree.maybe_error.
:- import_module cord.
:- import_module list.
:- import_module term.
:- import_module varset.
%---------------------------------------------------------------------------%
% parse_possibly_repeated_vars(Term, VarSet, ContextPieces, MaybeVars):
%
% Parse Term as a list of quantified variables Vars. If successful,
% return ok1(Vars). If not, return an error message that has
% ContextPieces as a prefix.
%
:- pred parse_possibly_repeated_vars(term(T)::in, varset(T)::in,
cord(format_component)::in, maybe1(list(var(T)))::out) is det.
% parse_vars(Term, VarSet, ContextPieces, MaybeVars):
%
% The same as parse_possibly_repeated_vars, but generate an error
% if a variable is in the list more than once.
%
:- pred parse_vars(term(T)::in, varset(T)::in,
cord(format_component)::in, maybe1(list(var(T)))::out) is det.
:- type plain_state_vars(T)
---> plain_state_vars(
list(var(T)), % plain variables
list(var(T)) % !V state variables
).
% parse_vars_state_vars(Term, VarSet, ContextPieces, MaybeVars):
%
% The same as parse_vars, but parse not just ordinary variables V,
% but also state variables !SV.
%
:- pred parse_vars_state_vars(term(T)::in, varset(T)::in,
cord(format_component)::in, maybe1(plain_state_vars(T))::out) is det.
:- type plain_state_dot_colon_vars(T)
---> plain_state_dot_colon_vars(
list(var(T)), % plain variables
list(var(T)), % !V state variables
list(var(T)), % !.V state variables
list(var(T)) % !:V state variables
).
% parse_vars_state_dot_colon_vars(Term, VarSet, ContextPieces, MaybeVars):
%
% The same as parse_vars, but parse not just ordinary variables V,
% but also state variables !SV, !.SV and !:SV.
%
:- pred parse_vars_state_dot_colon_vars(term(T)::in, varset(T)::in,
cord(format_component)::in, maybe1(plain_state_dot_colon_vars(T))::out)
is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module parse_tree.parse_tree_out_term.
%---------------------------------------------------------------------------%
parse_possibly_repeated_vars(Term, VarSet, ContextPieces, MaybeVars) :-
( if Term = term.functor(term.atom("[]"), [], _) then
MaybeVars = ok1([])
else if Term = term.functor(term.atom("[|]"), [HeadTerm, TailTerm], _) then
(
HeadTerm = term.variable(HeadVar0, _),
MaybeHeadVar = ok1(HeadVar0)
;
HeadTerm = term.functor(_, _, _),
generate_unexpected_term_message(ContextPieces, VarSet,
"a variable", HeadTerm, Spec),
MaybeHeadVar = error1([Spec])
),
parse_possibly_repeated_vars(TailTerm, VarSet, ContextPieces,
MaybeTailVars),
( if
MaybeHeadVar = ok1(HeadVar),
MaybeTailVars = ok1(TailVars)
then
MaybeVars = ok1([HeadVar | TailVars])
else
Specs = get_any_errors1(MaybeHeadVar) ++
get_any_errors1(MaybeTailVars),
MaybeVars = error1(Specs)
)
else
generate_unexpected_term_message(ContextPieces, VarSet,
"a list of variables", Term, Spec),
MaybeVars = error1([Spec])
).
parse_vars(Term, VarSet, ContextPieces, MaybeVars) :-
( if Term = functor(atom("[]"), [], _) then
MaybeVars = ok1([])
else if Term = functor(atom("[|]"), [HeadTerm, TailTerm], _) then
(
HeadTerm = variable(HeadVar0, _),
MaybeHeadVar = ok1(HeadVar0)
;
HeadTerm = functor(_, _, _),
generate_unexpected_term_message(ContextPieces, VarSet,
"a variable", HeadTerm, HeadSpec),
MaybeHeadVar = error1([HeadSpec])
),
parse_vars(TailTerm, VarSet, ContextPieces, MaybeTailVars),
( if
MaybeHeadVar = ok1(HeadVar),
MaybeTailVars = ok1(TailVars)
then
( if list.member(HeadVar, TailVars) then
generate_repeated_var_msg(ContextPieces, VarSet,
HeadTerm, Spec),
MaybeVars = error1([Spec])
else
Vars = [HeadVar | TailVars],
MaybeVars = ok1(Vars)
)
else
Specs = get_any_errors1(MaybeHeadVar) ++
get_any_errors1(MaybeTailVars),
MaybeVars = error1(Specs)
)
else
generate_unexpected_term_message(ContextPieces, VarSet,
"a list of variables", Term, Spec),
MaybeVars = error1([Spec])
).
%---------------------------------------------------------------------------%
:- type ordinary_state_var(T)
---> os_ordinary_var(var(T))
; os_state_var(var(T)).
parse_vars_state_vars(Term, VarSet, ContextPieces, MaybeVars) :-
( if Term = functor(atom("[]"), [], _) then
MaybeVars = ok1(plain_state_vars([], []))
else if Term = functor(atom("[|]"), [HeadTerm, TailTerm], _) then
( if
(
HeadTerm = variable(V0, _),
VarKind0 = os_ordinary_var(V0)
;
HeadTerm = functor(atom("!"), [variable(SV0, _)], _),
VarKind0 = os_state_var(SV0)
)
then
MaybeHeadVar = ok1(VarKind0)
else
generate_unexpected_term_message(ContextPieces, VarSet,
"a variable or state variable", HeadTerm, HeadSpec),
MaybeHeadVar = error1([HeadSpec])
),
parse_vars_state_vars(TailTerm, VarSet, ContextPieces, MaybeTailVars),
( if
MaybeHeadVar = ok1(VarKind),
MaybeTailVars = ok1(plain_state_vars(TailVars, TailStateVars))
then
(
VarKind = os_ordinary_var(V),
( if list.member(V, TailVars) then
generate_repeated_var_msg(ContextPieces, VarSet,
HeadTerm, Spec),
MaybeVars = error1([Spec])
else
Vars = [V | TailVars],
MaybeVars = ok1(plain_state_vars(Vars, TailStateVars))
)
;
VarKind = os_state_var(SV),
( if list.member(SV, TailStateVars) then
generate_repeated_state_var_msg(ContextPieces, VarSet,
HeadTerm, Spec),
MaybeVars = error1([Spec])
else
StateVars = [SV | TailStateVars],
MaybeVars = ok1(plain_state_vars(TailVars, StateVars))
)
)
else
Specs = get_any_errors1(MaybeHeadVar) ++
get_any_errors1(MaybeTailVars),
MaybeVars = error1(Specs)
)
else
generate_unexpected_term_message(ContextPieces, VarSet,
"a list of variables and/or state variables", Term, Spec),
MaybeVars = error1([Spec])
).
%---------------------------------------------------------------------------%
:- type ordinary_state_dot_colon_var(T)
---> osdc_ordinary_var(var(T))
; osdc_state_var(var(T))
; osdc_dot_var(var(T))
; osdc_colon_var(var(T)).
parse_vars_state_dot_colon_vars(Term, VarSet, ContextPieces, MaybeVars) :-
( if Term = functor(atom("[]"), [], _) then
MaybeVars = ok1(plain_state_dot_colon_vars([], [], [], []))
else if Term = functor(atom("[|]"), [HeadTerm, Tail], _) then
( if
(
HeadTerm = variable(V0, _),
VarKind0 = osdc_ordinary_var(V0)
;
HeadTerm = functor(atom("!"), [variable(SV0, _)], _),
VarKind0 = osdc_state_var(SV0)
;
HeadTerm = functor(atom("!."), [variable(SV0, _)], _),
VarKind0 = osdc_dot_var(SV0)
;
HeadTerm = functor(atom("!:"), [variable(SV0, _)], _),
VarKind0 = osdc_colon_var(SV0)
)
then
MaybeHeadVar = ok1(VarKind0)
else
generate_unexpected_term_message(ContextPieces, VarSet,
"a variable or state variable", HeadTerm, HeadSpec),
MaybeHeadVar = error1([HeadSpec])
),
parse_vars_state_dot_colon_vars(Tail, VarSet, ContextPieces,
MaybeTailVars),
( if
MaybeHeadVar = ok1(VarKind),
MaybeTailVars = ok1(plain_state_dot_colon_vars(TailVars,
TailStateVars, TailDotVars, TailColonVars))
then
(
VarKind = osdc_ordinary_var(V),
( if list.member(V, TailVars) then
generate_repeated_var_msg(ContextPieces, VarSet,
HeadTerm, Spec),
MaybeVars = error1([Spec])
else
Vars = [V | TailVars],
MaybeVars = ok1(plain_state_dot_colon_vars(Vars,
TailStateVars, TailDotVars, TailColonVars))
)
;
VarKind = osdc_state_var(SV),
( if
( list.member(SV, TailStateVars )
; list.member(SV, TailDotVars )
; list.member(SV, TailColonVars )
)
then
generate_repeated_var_msg(ContextPieces, VarSet,
HeadTerm, Spec),
MaybeVars = error1([Spec])
else
StateVars = [SV | TailStateVars],
MaybeVars = ok1(plain_state_dot_colon_vars(TailVars,
StateVars, TailDotVars, TailColonVars))
)
;
VarKind = osdc_dot_var(SV),
( if
( list.member(SV, TailStateVars )
; list.member(SV, TailDotVars )
; list.member(SV, TailColonVars )
)
then
generate_repeated_var_msg(ContextPieces, VarSet,
HeadTerm, Spec),
MaybeVars = error1([Spec])
else
DotVars = [SV | TailDotVars],
MaybeVars = ok1(plain_state_dot_colon_vars(TailVars,
TailStateVars, DotVars, TailColonVars))
)
;
VarKind = osdc_colon_var(SV),
( if
( list.member(SV, TailStateVars )
; list.member(SV, TailDotVars )
; list.member(SV, TailColonVars )
)
then
generate_repeated_var_msg(ContextPieces, VarSet,
HeadTerm, Spec),
MaybeVars = error1([Spec])
else
ColonVars = [SV | TailColonVars],
MaybeVars = ok1(plain_state_dot_colon_vars(TailVars,
TailStateVars, TailDotVars, ColonVars))
)
)
else
HeadSpecs = get_any_errors1(MaybeHeadVar),
TailSpecs = get_any_errors1(MaybeTailVars),
MaybeVars = error1(HeadSpecs ++ TailSpecs)
)
else
generate_unexpected_term_message(ContextPieces, VarSet,
"a list of variables and/or state variables", Term, Spec),
MaybeVars = error1([Spec])
).
%---------------------------------------------------------------------------%
:- pred generate_repeated_var_msg(cord(format_component)::in,
varset(T)::in, term(T)::in, error_spec::out) is det.
generate_repeated_var_msg(ContextPieces, VarSet, Term, Spec) :-
TermStr = describe_error_term(VarSet, Term),
Pieces = cord.list(ContextPieces) ++ [lower_case_next_if_not_first,
words("Repeated variable"), words(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]).
:- pred generate_repeated_state_var_msg(cord(format_component)::in,
varset(T)::in, term(T)::in, error_spec::out) is det.
generate_repeated_state_var_msg(ContextPieces, VarSet, Term, Spec) :-
TermStr = describe_error_term(VarSet, Term),
Pieces = cord.list(ContextPieces) ++ [lower_case_next_if_not_first,
words("Repeated state variable"), words(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]).
:- pred generate_unexpected_term_message(cord(format_component)::in,
varset(T)::in, string::in, term(T)::in, error_spec::out) is det.
generate_unexpected_term_message(ContextPieces, VarSet, Expected, Term,
Spec) :-
TermStr = describe_error_term(VarSet, Term),
Pieces = cord.list(ContextPieces) ++ [lower_case_next_if_not_first,
words("Expected"), words(Expected), suffix(","),
words("got"), quote(TermStr), suffix("."), nl],
Spec = error_spec(severity_error, phase_term_to_parse_tree,
[simple_msg(get_term_context(Term), [always(Pieces)])]).
%---------------------------------------------------------------------------%
:- end_module parse_tree.parse_vars.
%---------------------------------------------------------------------------%