mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
Estimated hours taken: 6 Branches: main compiler/*.m: Convert almost all remaining modules in the compiler to use "$module, $pred" instead of "this_file" in error messages. In a few cases, the old error message was misleading, since it contained an incorrect, out-of-date or cut-and-pasted predicate name. tests/invalid/unresolved_overloading.err_exp: Update an expected output containing an updated error message.
657 lines
29 KiB
Mathematica
657 lines
29 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1993-2011 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module hlds.make_hlds.add_clause.
|
|
:- interface.
|
|
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.make_hlds.qual_info.
|
|
:- import_module hlds.quantification.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module parse_tree.error_util.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
:- import_module list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred module_add_clause(prog_varset::in, pred_or_func::in, sym_name::in,
|
|
list(prog_term)::in, goal::in, import_status::in, prog_context::in,
|
|
maybe(int)::in, goal_type::in, module_info::in, module_info::out,
|
|
qual_info::in, qual_info::out,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
:- pred clauses_info_add_clause(clause_applicable_modes::in, list(proc_id)::in,
|
|
prog_varset::in, tvarset::in, list(prog_term)::in, goal::in,
|
|
prog_context::in, maybe(int)::in, import_status::in, pred_or_func::in,
|
|
arity::in, goal_type::in, hlds_goal::out, prog_varset::out, tvarset::out,
|
|
clauses_info::in, clauses_info::out, list(quant_warning)::out,
|
|
module_info::in, module_info::out, qual_info::in, qual_info::out,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.clause_to_proc.
|
|
:- import_module check_hlds.mode_errors.
|
|
:- import_module hlds.goal_util.
|
|
:- import_module hlds.hlds_args.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module hlds.hlds_error_util.
|
|
:- import_module hlds.hlds_out.
|
|
:- import_module hlds.hlds_out.hlds_out_goal.
|
|
:- import_module hlds.hlds_out.hlds_out_util.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module hlds.hlds_rtti.
|
|
:- import_module hlds.make_hlds.add_pragma.
|
|
:- import_module hlds.make_hlds.add_pred.
|
|
:- import_module hlds.make_hlds.field_access.
|
|
:- import_module hlds.make_hlds.goal_expr_to_goal.
|
|
:- import_module hlds.make_hlds.make_hlds_warn.
|
|
:- import_module hlds.make_hlds.state_var.
|
|
:- import_module hlds.make_hlds.superhomogeneous.
|
|
:- import_module hlds.pred_table.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
:- import_module parse_tree.mercury_to_mercury.
|
|
:- import_module parse_tree.module_qual.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_io_util.
|
|
:- import_module parse_tree.prog_mode.
|
|
:- import_module parse_tree.prog_out.
|
|
:- import_module parse_tree.prog_util.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module bool.
|
|
:- import_module int.
|
|
:- import_module io.
|
|
:- import_module map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module varset.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
module_add_clause(ClauseVarSet, PredOrFunc, PredName, Args0, Body, Status,
|
|
Context, MaybeSeqNum, GoalType, !ModuleInfo, !QualInfo, !Specs) :-
|
|
( illegal_state_var_func_result(PredOrFunc, Args0, SVar) ->
|
|
IllegalSVarResult = yes(SVar)
|
|
;
|
|
IllegalSVarResult = no
|
|
),
|
|
ArityAdjustment = ( if IllegalSVarResult = yes(_) then -1 else 0 ),
|
|
expand_bang_states(Args0, Args),
|
|
|
|
% Lookup the pred declaration in the predicate table.
|
|
% (If it's not there, call maybe_undefined_pred_error and insert
|
|
% an implicit declaration for the predicate.)
|
|
module_info_get_name(!.ModuleInfo, ModuleName),
|
|
list.length(Args, Arity0),
|
|
Arity = Arity0 + ArityAdjustment,
|
|
some [!PredInfo, !PredicateTable] (
|
|
module_info_get_predicate_table(!.ModuleInfo, !:PredicateTable),
|
|
(
|
|
predicate_table_search_pf_sym_arity(!.PredicateTable,
|
|
is_fully_qualified, PredOrFunc, PredName, Arity, [PredId0])
|
|
->
|
|
PredId = PredId0,
|
|
( GoalType = goal_type_promise(_) ->
|
|
NameString = sym_name_to_string(PredName),
|
|
string.format("%s %s %s (%s).\n",
|
|
[s("Attempted to introduce a predicate"),
|
|
s("for a promise with an identical"),
|
|
s("name to an existing predicate"),
|
|
s(NameString)], UnexpectedMsg),
|
|
unexpected($module, $pred, UnexpectedMsg)
|
|
;
|
|
true
|
|
)
|
|
;
|
|
% A promise will not have a corresponding pred declaration.
|
|
( GoalType = goal_type_promise(_) ->
|
|
HeadVars = term.term_list_to_var_list(Args),
|
|
preds_add_implicit_for_assertion(HeadVars, !.ModuleInfo,
|
|
ModuleName, PredName, Arity, Status, Context, PredOrFunc,
|
|
PredId, !PredicateTable),
|
|
module_info_set_predicate_table(!.PredicateTable, !ModuleInfo)
|
|
;
|
|
preds_add_implicit_report_error(ModuleName, PredOrFunc,
|
|
PredName, Arity, Status, no, Context,
|
|
origin_user(PredName), "clause", PredId, !ModuleInfo,
|
|
!Specs)
|
|
)
|
|
),
|
|
% Lookup the pred_info for this pred, add the clause to the
|
|
% clauses_info in the pred_info, if there are no modes add an
|
|
% `infer_modes' marker, and then save the pred_info.
|
|
module_info_get_predicate_table(!.ModuleInfo, !:PredicateTable),
|
|
predicate_table_get_preds(!.PredicateTable, Preds0),
|
|
map.lookup(Preds0, PredId, !:PredInfo),
|
|
|
|
trace [io(!IO)] (
|
|
some [Globals] (
|
|
module_info_get_globals(!.ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, very_verbose, VeryVerbose),
|
|
(
|
|
VeryVerbose = yes,
|
|
pred_info_get_clauses_info(!.PredInfo, MsgClauses),
|
|
NumClauses = num_clauses_in_clauses_rep(
|
|
MsgClauses ^ cli_rep),
|
|
io.format("%% Processing clause %d for ",
|
|
[i(NumClauses + 1)], !IO),
|
|
write_pred_or_func(PredOrFunc, !IO),
|
|
io.write_string(" `", !IO),
|
|
list.length(Args, PredArity0),
|
|
PredArity = PredArity0 + ArityAdjustment,
|
|
adjust_func_arity(PredOrFunc, OrigArity, PredArity),
|
|
prog_out.write_sym_name_and_arity(PredName/OrigArity, !IO),
|
|
io.write_string("'...\n", !IO)
|
|
;
|
|
VeryVerbose = no
|
|
)
|
|
)
|
|
),
|
|
|
|
% Opt_imported preds are initially tagged as imported, and are tagged
|
|
% as opt_imported only if/when we see a clause for them.
|
|
( Status = status_opt_imported ->
|
|
pred_info_set_import_status(status_opt_imported, !PredInfo),
|
|
pred_info_get_markers(!.PredInfo, InitMarkers0),
|
|
add_marker(marker_calls_are_fully_qualified,
|
|
InitMarkers0, InitMarkers),
|
|
pred_info_set_markers(InitMarkers, !PredInfo)
|
|
;
|
|
true
|
|
),
|
|
(
|
|
IllegalSVarResult = yes(StateVar),
|
|
report_illegal_func_svar_result(Context, ClauseVarSet, StateVar,
|
|
!Specs)
|
|
;
|
|
IllegalSVarResult = no,
|
|
(
|
|
% User-supplied clauses for field access functions are not
|
|
% allowed -- the clauses are always generated by the compiler.
|
|
%
|
|
PredOrFunc = pf_function,
|
|
adjust_func_arity(pf_function, FuncArity, Arity),
|
|
is_field_access_function_name(!.ModuleInfo, PredName,
|
|
FuncArity, _, _),
|
|
|
|
% Don't report errors for clauses for field access
|
|
% function clauses in `.opt' files.
|
|
Status \= status_opt_imported
|
|
->
|
|
CallId = simple_call_id(PredOrFunc, PredName, Arity),
|
|
MainPieces = [
|
|
words("Error: clause for automatically generated"),
|
|
words("field access"), simple_call(CallId),
|
|
suffix("."), nl],
|
|
VerbosePieces = [words("Clauses for field access functions"),
|
|
words("are automatically generated by the compiler."),
|
|
words("To supply your own definition for a field access"),
|
|
words("function, for example to check the input"),
|
|
words("to a field update, give the field"),
|
|
words("of the constructor a different name.")],
|
|
Msg = simple_msg(Context,
|
|
[always(MainPieces), verbose_only(VerbosePieces)]),
|
|
Spec = error_spec(severity_error, phase_parse_tree_to_hlds,
|
|
[Msg]),
|
|
!:Specs = [Spec | !.Specs]
|
|
;
|
|
pred_info_is_builtin(!.PredInfo)
|
|
->
|
|
% When bootstrapping a change that defines a builtin using
|
|
% normal Mercury code, we need to disable the generation
|
|
% of the error message, and just ignore the definition.
|
|
some [Globals] (
|
|
module_info_get_globals(!.ModuleInfo, Globals),
|
|
globals.lookup_bool_option(Globals, allow_defn_of_builtins,
|
|
AllowDefnOfBuiltin)
|
|
),
|
|
(
|
|
AllowDefnOfBuiltin = no,
|
|
Msg = simple_msg(Context,
|
|
[always([words("Error: clause for builtin.")])]),
|
|
Spec = error_spec(severity_error, phase_parse_tree_to_hlds,
|
|
[Msg]),
|
|
!:Specs = [Spec | !.Specs]
|
|
;
|
|
AllowDefnOfBuiltin = yes
|
|
)
|
|
;
|
|
pred_info_get_clauses_info(!.PredInfo, Clauses0),
|
|
pred_info_get_typevarset(!.PredInfo, TVarSet0),
|
|
maybe_add_default_func_mode(!PredInfo, _),
|
|
select_applicable_modes(Args, ClauseVarSet, Status, Context,
|
|
PredId, !.PredInfo, ArgTerms, ProcIdsForThisClause,
|
|
AllProcIds, !ModuleInfo, !QualInfo, !Specs),
|
|
clauses_info_add_clause(ProcIdsForThisClause, AllProcIds,
|
|
ClauseVarSet, TVarSet0, ArgTerms, Body,
|
|
Context, MaybeSeqNum, Status, PredOrFunc, Arity,
|
|
GoalType, Goal, VarSet, TVarSet, Clauses0, Clauses,
|
|
Warnings, !ModuleInfo, !QualInfo, !Specs),
|
|
pred_info_set_clauses_info(Clauses, !PredInfo),
|
|
( GoalType = goal_type_promise(PromiseType) ->
|
|
pred_info_set_goal_type(goal_type_promise(PromiseType),
|
|
!PredInfo)
|
|
;
|
|
pred_info_update_goal_type(goal_type_clause, !PredInfo)
|
|
),
|
|
pred_info_set_typevarset(TVarSet, !PredInfo),
|
|
pred_info_get_arg_types(!.PredInfo, _ArgTVarSet, ExistQVars,
|
|
ArgTypes),
|
|
pred_info_set_arg_types(TVarSet, ExistQVars, ArgTypes,
|
|
!PredInfo),
|
|
|
|
% Check if there are still no modes for the predicate, and
|
|
% if so, set the `infer_modes' flag for that predicate.
|
|
|
|
ProcIds = pred_info_all_procids(!.PredInfo),
|
|
(
|
|
ProcIds = [],
|
|
pred_info_get_markers(!.PredInfo, EndMarkers0),
|
|
add_marker(marker_infer_modes, EndMarkers0, EndMarkers),
|
|
pred_info_set_markers(EndMarkers, !PredInfo)
|
|
;
|
|
ProcIds = [_ | _]
|
|
),
|
|
map.det_update(PredId, !.PredInfo, Preds0, Preds),
|
|
predicate_table_set_preds(Preds, !PredicateTable),
|
|
module_info_set_predicate_table(!.PredicateTable, !ModuleInfo),
|
|
( Status = status_opt_imported ->
|
|
true
|
|
;
|
|
% Warn about singleton variables.
|
|
SimpleCallId = simple_call_id(PredOrFunc, PredName, Arity),
|
|
warn_singletons(VarSet, SimpleCallId, !.ModuleInfo, Goal,
|
|
!Specs),
|
|
% Warn about variables with overlapping scopes.
|
|
warn_overlap(Warnings, VarSet, SimpleCallId, !Specs)
|
|
)
|
|
)
|
|
)
|
|
).
|
|
|
|
% Extract the mode annotations (if any) from the clause arguments,
|
|
% and determine which mode(s) this clause should apply to.
|
|
%
|
|
:- pred select_applicable_modes(list(prog_term)::in, prog_varset::in,
|
|
import_status::in, prog_context::in, pred_id::in, pred_info::in,
|
|
list(prog_term)::out, clause_applicable_modes::out, list(proc_id)::out,
|
|
module_info::in, module_info::out, qual_info::in, qual_info::out,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
select_applicable_modes(Args0, VarSet, Status, Context, PredId, PredInfo,
|
|
Args, ApplProcIds, AllProcIds, !ModuleInfo, !QualInfo, !Specs) :-
|
|
AllProcIds = pred_info_all_procids(PredInfo),
|
|
get_mode_annotations(Args0, Args, empty, ModeAnnotations),
|
|
(
|
|
ModeAnnotations = modes(ModeList0),
|
|
|
|
% The user specified some mode annotations on this clause.
|
|
% First module-qualify the mode annotations. The annotations on
|
|
% clauses from `.opt' files will already be fully module qualified.
|
|
|
|
( Status = status_opt_imported ->
|
|
ModeList = ModeList0
|
|
;
|
|
qual_info_get_mq_info(!.QualInfo, MQInfo0),
|
|
qualify_clause_mode_list(ModeList0, ModeList, Context,
|
|
MQInfo0, MQInfo, !Specs),
|
|
qual_info_set_mq_info(MQInfo, !QualInfo)
|
|
),
|
|
|
|
% Now find the procedure which matches these mode annotations.
|
|
pred_info_get_procedures(PredInfo, Procs),
|
|
map.to_assoc_list(Procs, ExistingProcs),
|
|
(
|
|
get_procedure_matching_declmodes_with_renaming(ExistingProcs,
|
|
ModeList, !.ModuleInfo, ProcId)
|
|
->
|
|
ApplProcIds = selected_modes([ProcId])
|
|
;
|
|
undeclared_mode_error(ModeList, VarSet, PredId, PredInfo,
|
|
!.ModuleInfo, Context, !Specs),
|
|
% Apply the clause to all modes.
|
|
% XXX Would it be better to apply it to none?
|
|
ApplProcIds = selected_modes(AllProcIds)
|
|
)
|
|
;
|
|
( ModeAnnotations = empty
|
|
; ModeAnnotations = none
|
|
),
|
|
( pred_info_pragma_goal_type(PredInfo) ->
|
|
% We are only allowed to mix foreign procs and
|
|
% mode specific clauses, so make this clause
|
|
% mode specific but apply to all modes.
|
|
ApplProcIds = selected_modes(AllProcIds)
|
|
;
|
|
ApplProcIds = all_modes
|
|
)
|
|
;
|
|
ModeAnnotations = mixed,
|
|
PredIdStr = pred_id_to_string(!.ModuleInfo, PredId),
|
|
Pieces = [words("In clause for"), fixed(PredIdStr), suffix(":"), nl,
|
|
words("syntax error: some but not all arguments"),
|
|
words("have mode annotations."), nl],
|
|
Msg = simple_msg(Context, [always(Pieces)]),
|
|
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
|
|
!:Specs = [Spec | !.Specs],
|
|
|
|
% Apply the clause to all modes.
|
|
% XXX Would it be better to apply it to none?
|
|
ApplProcIds = selected_modes(AllProcIds)
|
|
).
|
|
|
|
:- pred undeclared_mode_error(list(mer_mode)::in, prog_varset::in,
|
|
pred_id::in, pred_info::in, module_info::in, prog_context::in,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
undeclared_mode_error(ModeList, VarSet, PredId, PredInfo, ModuleInfo, Context,
|
|
!Specs) :-
|
|
PredIdPieces = describe_one_pred_name(ModuleInfo,
|
|
should_not_module_qualify, PredId),
|
|
strip_builtin_qualifiers_from_mode_list(ModeList, StrippedModeList),
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
Name = pred_info_name(PredInfo),
|
|
MaybeDet = no,
|
|
SubDeclStr = mercury_mode_subdecl_to_string(PredOrFunc,
|
|
varset.coerce(VarSet), unqualified(Name), StrippedModeList,
|
|
MaybeDet, Context),
|
|
|
|
MainPieces = [words("In clause for")] ++ PredIdPieces ++ [suffix(":"), nl,
|
|
words("error: mode annotation specifies undeclared mode"),
|
|
quote(SubDeclStr), suffix("."), nl],
|
|
ProcIds = pred_info_all_procids(PredInfo),
|
|
(
|
|
ProcIds = [],
|
|
VerbosePieces = [words("(There are no declared modes for this"),
|
|
p_or_f(PredOrFunc), suffix(".)"), nl]
|
|
;
|
|
ProcIds = [ProcIdsHead | ProcIdsTail],
|
|
(
|
|
ProcIdsTail = [],
|
|
VerbosePieces = [words("The declared mode for this"),
|
|
p_or_f(PredOrFunc), words("is:"),
|
|
nl_indent_delta(1)] ++
|
|
mode_decl_for_pred_info_to_pieces(PredInfo, ProcIdsHead) ++
|
|
[nl_indent_delta(-1)]
|
|
;
|
|
ProcIdsTail = [_ | _],
|
|
VerbosePieces = [words("The declared modes for this"),
|
|
p_or_f(PredOrFunc), words("are the following:"),
|
|
nl_indent_delta(1)] ++
|
|
component_list_to_line_pieces(
|
|
list.map(mode_decl_for_pred_info_to_pieces(PredInfo),
|
|
ProcIds),
|
|
[]) ++
|
|
[nl_indent_delta(-1)]
|
|
)
|
|
),
|
|
Msg = simple_msg(Context,
|
|
[always(MainPieces), verbose_only(VerbosePieces)]),
|
|
Spec = error_spec(severity_error, phase_parse_tree_to_hlds, [Msg]),
|
|
!:Specs = [Spec | !.Specs].
|
|
|
|
:- func mode_decl_for_pred_info_to_pieces(pred_info, proc_id)
|
|
= list(format_component).
|
|
|
|
mode_decl_for_pred_info_to_pieces(PredInfo, ProcId) =
|
|
[words(":- mode"), words(mode_decl_to_string(ProcId, PredInfo)),
|
|
suffix(".")].
|
|
|
|
% Clauses can have mode annotations on them, to indicate that the
|
|
% clause should only be used for particular modes of a predicate.
|
|
% This type specifies the mode annotations on a clause.
|
|
:- type mode_annotations
|
|
---> empty % No arguments.
|
|
|
|
; none % One or more arguments,
|
|
% each without any mode annotations.
|
|
|
|
; modes(list(mer_mode))
|
|
% One or more arguments, each with a mode annotation.
|
|
|
|
; mixed. % Two or more arguments, including some with mode
|
|
% annotations and some without. (This is not allowed.)
|
|
|
|
% Extract the mode annotations (if any) from a list of arguments.
|
|
%
|
|
:- pred get_mode_annotations(list(prog_term)::in, list(prog_term)::out,
|
|
mode_annotations::in, mode_annotations::out) is det.
|
|
|
|
get_mode_annotations([], [], !Annotations).
|
|
get_mode_annotations([Arg0 | Args0], [Arg | Args], !Annotations) :-
|
|
get_mode_annotation(Arg0, Arg, MaybeAnnotation),
|
|
add_annotation(MaybeAnnotation, !Annotations),
|
|
get_mode_annotations(Args0, Args, !Annotations).
|
|
|
|
:- pred add_annotation(maybe(mer_mode)::in,
|
|
mode_annotations::in, mode_annotations::out) is det.
|
|
|
|
add_annotation(no, empty, none).
|
|
add_annotation(yes(Mode), empty, modes([Mode])).
|
|
add_annotation(no, modes(_ `with_type` list(mer_mode)), mixed).
|
|
add_annotation(yes(Mode), modes(Modes), modes(Modes ++ [Mode])).
|
|
add_annotation(no, none, none).
|
|
add_annotation(yes(_), none, mixed).
|
|
add_annotation(_, mixed, mixed).
|
|
|
|
% Extract the mode annotations (if any) from a single argument.
|
|
%
|
|
:- pred get_mode_annotation(prog_term::in, prog_term::out,
|
|
maybe(mer_mode)::out) is det.
|
|
|
|
get_mode_annotation(Arg0, Arg, MaybeAnnotation) :-
|
|
(
|
|
Arg0 = term.functor(term.atom("::"), [Arg1, ModeTerm], _),
|
|
convert_mode(allow_constrained_inst_var, term.coerce(ModeTerm), Mode)
|
|
->
|
|
Arg = Arg1,
|
|
MaybeAnnotation = yes(Mode)
|
|
;
|
|
Arg = Arg0,
|
|
MaybeAnnotation = no
|
|
).
|
|
|
|
clauses_info_add_clause(ApplModeIds0, AllModeIds, CVarSet, TVarSet0,
|
|
Args, Body, Context, MaybeSeqNum, Status, PredOrFunc, Arity,
|
|
GoalType, Goal, VarSet, TVarSet, !ClausesInfo, QuantWarnings,
|
|
!ModuleInfo, !QualInfo, !Specs) :-
|
|
!.ClausesInfo = clauses_info(VarSet0, ExplicitVarTypes0,
|
|
TVarNameMap0, InferredVarTypes, HeadVars, ClausesRep0, ItemNumbers0,
|
|
RttiVarMaps, HasForeignClauses),
|
|
IsEmpty = clause_list_is_empty(ClausesRep0),
|
|
(
|
|
IsEmpty = yes,
|
|
% Create the mapping from type variable name, used to rename
|
|
% type variables occurring in explicit type qualifications.
|
|
% The version of this mapping stored in the clauses_info should
|
|
% only contain type variables which occur in the argument types
|
|
% of the predicate. Type variables which only occur in explicit type
|
|
% qualifications are local to the clause in which they appear.
|
|
varset.create_name_var_map(TVarSet0, TVarNameMap)
|
|
;
|
|
IsEmpty = no,
|
|
TVarNameMap = TVarNameMap0
|
|
),
|
|
update_qual_info(TVarNameMap, TVarSet0, ExplicitVarTypes0, Status,
|
|
!QualInfo),
|
|
varset.merge_renaming(VarSet0, CVarSet, VarSet1, Renaming),
|
|
add_clause_transform(Renaming, HeadVars, Args, Body, Context, PredOrFunc,
|
|
Arity, GoalType, Goal0, VarSet1, VarSet,
|
|
QuantWarnings, StateVarWarnings, StateVarErrors,
|
|
!ModuleInfo, !QualInfo, !Specs),
|
|
qual_info_get_tvarset(!.QualInfo, TVarSet),
|
|
qual_info_get_found_syntax_error(!.QualInfo, FoundError),
|
|
qual_info_set_found_syntax_error(no, !QualInfo),
|
|
(
|
|
( FoundError = yes
|
|
; StateVarErrors = [_ | _]
|
|
)
|
|
->
|
|
% Don't insert clauses containing syntax errors into the clauses_info,
|
|
% because doing that would cause typecheck.m to report spurious type
|
|
% errors. Don't report singleton variable warnings if there were
|
|
% syntax errors.
|
|
!:Specs = StateVarErrors ++ !.Specs,
|
|
Goal = true_goal
|
|
;
|
|
Goal = Goal0,
|
|
|
|
% If we have foreign clauses, we should only add this clause
|
|
% for modes *not* covered by the foreign clauses.
|
|
(
|
|
HasForeignClauses = yes,
|
|
get_clause_list_any_order(ClausesRep0, AnyOrderClauseList),
|
|
ForeignModeIds = list.condense(list.filter_map(
|
|
(func(C) = ProcIds is semidet :-
|
|
C ^ clause_lang = impl_lang_foreign(_),
|
|
ApplProcIds = C ^ clause_applicable_procs,
|
|
(
|
|
ApplProcIds = all_modes,
|
|
unexpected($module, $pred, "all_modes foreign_proc")
|
|
;
|
|
ApplProcIds = selected_modes(ProcIds)
|
|
)
|
|
),
|
|
AnyOrderClauseList)),
|
|
(
|
|
ApplModeIds0 = all_modes,
|
|
ModeIds0 = AllModeIds
|
|
;
|
|
ApplModeIds0 = selected_modes(ModeIds0)
|
|
),
|
|
ModeIds = list.delete_elems(ModeIds0, ForeignModeIds),
|
|
(
|
|
ModeIds = [],
|
|
ClausesRep = ClausesRep0
|
|
;
|
|
ModeIds = [_ | _],
|
|
ApplicableModeIds = selected_modes(ModeIds),
|
|
Clause = clause(ApplicableModeIds, Goal, impl_lang_mercury,
|
|
Context, StateVarWarnings),
|
|
add_clause(Clause, ClausesRep0, ClausesRep)
|
|
)
|
|
;
|
|
HasForeignClauses = no,
|
|
Clause = clause(ApplModeIds0, Goal, impl_lang_mercury, Context,
|
|
StateVarWarnings),
|
|
add_clause(Clause, ClausesRep0, ClausesRep)
|
|
),
|
|
qual_info_get_var_types(!.QualInfo, ExplicitVarTypes),
|
|
add_clause_item_number(MaybeSeqNum, Context, item_is_clause,
|
|
ItemNumbers0, ItemNumbers),
|
|
!:ClausesInfo = clauses_info(VarSet, ExplicitVarTypes, TVarNameMap,
|
|
InferredVarTypes, HeadVars, ClausesRep, ItemNumbers,
|
|
RttiVarMaps, HasForeignClauses)
|
|
).
|
|
|
|
% Args0 has already had !S arguments replaced by a !.S, !:S argument pair.
|
|
%
|
|
:- pred add_clause_transform(prog_var_renaming::in,
|
|
proc_arg_vector(prog_var)::in, list(prog_term)::in, goal::in,
|
|
prog_context::in, pred_or_func::in, arity::in, goal_type::in,
|
|
hlds_goal::out, prog_varset::in, prog_varset::out,
|
|
list(quant_warning)::out, list(error_spec)::out, list(error_spec)::out,
|
|
module_info::in, module_info::out, qual_info::in, qual_info::out,
|
|
list(error_spec)::in, list(error_spec)::out) is det.
|
|
|
|
add_clause_transform(Renaming, HeadVars, Args0, ParseBody, Context, PredOrFunc,
|
|
Arity, GoalType, Goal, !VarSet, QuantWarnings, StateVarWarnings,
|
|
StateVarErrors, !ModuleInfo, !QualInfo, !Specs) :-
|
|
some [!SInfo, !SVarState, !SVarStore] (
|
|
HeadVarList = proc_arg_vector_to_list(HeadVars),
|
|
rename_vars_in_term_list(need_not_rename, Renaming, Args0, Args1),
|
|
svar_prepare_for_clause_head(Args1, Args, !VarSet, FinalSVarMap,
|
|
!:SVarState, !:SVarStore, !Specs),
|
|
InitialSVarState = !.SVarState,
|
|
( GoalType = goal_type_promise(_) ->
|
|
HeadGoal = true_goal
|
|
;
|
|
ArgContext = ac_head(PredOrFunc, Arity),
|
|
HeadGoal0 = true_goal,
|
|
insert_arg_unifications(HeadVarList, Args, Context, ArgContext,
|
|
HeadGoal0, HeadGoal1, _, !SVarState, !SVarStore, !VarSet,
|
|
!ModuleInfo, !QualInfo, !Specs),
|
|
% The only pass that pays attention to the from_head feature,
|
|
% switch_detection, only does so on kinds of hlds_goal_exprs
|
|
% that do not occur in from_ground_term scopes, which we have
|
|
% just marked as from_ground_term_construct. However, later
|
|
% passes may convert some of the unifications inside these scopes
|
|
% to calls, and switch detection *does* care about from_head
|
|
% on calls, and it looks inside all scopes except those of the
|
|
% from_ground_term_construct kind. Therefore any code that can be
|
|
% executed between now and switch detection that converts a
|
|
% from_ground_term_construct scope to another kind of scope
|
|
% should attach any from_head feature present on the scope
|
|
% to all its subgoals.
|
|
attach_features_to_all_goals([feature_from_head],
|
|
do_not_attach_in_from_ground_term, HeadGoal1, HeadGoal)
|
|
),
|
|
transform_goal_expr_context_to_goal(loc_whole_goal, ParseBody,
|
|
Renaming, BodyGoal, _, !SVarState, !SVarStore, !VarSet,
|
|
!ModuleInfo, !QualInfo, !Specs),
|
|
|
|
trace [compiletime(flag("debug-statevar-lambda")), io(!IO)] (
|
|
io.write_string("\nCLAUSE HEAD\n", !IO),
|
|
io.write_string("args before:\n", !IO),
|
|
io.write_list(Args0, "\n", io.write, !IO),
|
|
io.nl(!IO),
|
|
io.write_string("args renamed:\n", !IO),
|
|
io.write_list(Args1, "\n", io.write, !IO),
|
|
io.nl(!IO),
|
|
io.write_string("args after:\n", !IO),
|
|
io.write_list(Args, "\n", io.write, !IO),
|
|
io.nl(!IO),
|
|
io.write_string("head vars:\n", !IO),
|
|
io.write(HeadVarList, !IO),
|
|
io.nl(!IO),
|
|
io.write_string("arg unifies:\n", !IO),
|
|
dump_goal(!.ModuleInfo, !.VarSet, HeadGoal, !IO),
|
|
io.nl(!IO),
|
|
io.write_string("clause body:\n", !IO),
|
|
dump_goal(!.ModuleInfo, !.VarSet, BodyGoal, !IO),
|
|
io.nl(!IO),
|
|
some [FinalSVarList] (
|
|
map.to_assoc_list(FinalSVarMap, FinalSVarList),
|
|
io.write_string("FinalSVarMap:\n", !IO),
|
|
io.write(FinalSVarList, !IO),
|
|
io.nl(!IO)
|
|
)
|
|
),
|
|
|
|
FinalSVarState = !.SVarState,
|
|
svar_finish_clause_body(Context, FinalSVarMap,
|
|
[HeadGoal, BodyGoal], Goal0, InitialSVarState, FinalSVarState,
|
|
!.SVarStore, StateVarWarnings, StateVarErrors),
|
|
|
|
qual_info_get_var_types(!.QualInfo, VarTypes0),
|
|
% The RTTI varmaps here are just a dummy value, because the real ones
|
|
% are not introduced until polymorphism.
|
|
rtti_varmaps_init(EmptyRttiVarmaps),
|
|
% XXX It should be possible to exploit the fact that lambda expressions
|
|
% are not yet recognized as such inside from_ground_term scopes.
|
|
implicitly_quantify_clause_body_general(
|
|
ordinary_nonlocals_maybe_lambda,
|
|
HeadVarList, QuantWarnings, Goal0, Goal,
|
|
!VarSet, VarTypes0, VarTypes, EmptyRttiVarmaps, _),
|
|
qual_info_set_var_types(VarTypes, !QualInfo)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module hlds.make_hlds.add_clause.
|
|
%-----------------------------------------------------------------------------%
|