mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-13 04:44:39 +00:00
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.
362 lines
14 KiB
Mathematica
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.
|
|
%---------------------------------------------------------------------------%
|