mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-10 03:13:46 +00:00
Estimated hours taken: 6 Branches: main This diff changes modes.m, unique_modes.m and mode_info.m to make them easier to read and to maintain, but contains no changes in algorithms whatsoever. compiler/modes.m: compiler/unique_modes.m: compiler/mode_info.m: Convert these modules to our current coding standards. Use state variable notation when appropriate, reordering arguments as necessary. Delete predicates whose only purpose was to ease programming with DCGs. Remove the IO state from the mode_info structure, and pass it separately to the (relatively few) predicates that need it. This avoids using complicated (and as yet unsupported) modes or lying to the compiler (we used to do the latter), and we are no longer forced into that choice by being limited to a single hidden (DCG) variable. Use more expressive variable names and factor out code as appropriate. compiler/*.m: Conform to the changes in the above two modules.
1207 lines
45 KiB
Mathematica
1207 lines
45 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-2003 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.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% File: mode_errors.m.
|
|
% Main author: fjh.
|
|
|
|
% This module contains all the error-reporting routines for the
|
|
% mode-checker.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds__mode_errors.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds__hlds_data.
|
|
:- import_module hlds__hlds_pred.
|
|
:- import_module hlds__hlds_module.
|
|
:- import_module hlds__hlds_goal.
|
|
:- import_module parse_tree__prog_data.
|
|
:- import_module check_hlds__mode_info.
|
|
:- import_module parse_tree__inst.
|
|
|
|
:- import_module bool, set, assoc_list, list, io.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- type merge_context
|
|
---> disj
|
|
; if_then_else.
|
|
|
|
:- type merge_errors == assoc_list(prog_var, list(inst)).
|
|
|
|
:- type delayed_goal
|
|
---> delayed_goal(
|
|
set(prog_var), % The vars it's waiting on
|
|
mode_error_info,% The reason it can't be scheduled
|
|
hlds_goal % The goal itself
|
|
).
|
|
|
|
:- type mode_error
|
|
---> mode_error_disj(merge_context, merge_errors)
|
|
% different arms of a disjunction result in
|
|
% different insts for some non-local variables
|
|
; mode_error_par_conj(merge_errors)
|
|
% different arms of a parallel conj result in
|
|
% mutually exclusive bindings - ie the process
|
|
% of unifying the instmaps from the end of each
|
|
% branch failed.
|
|
; mode_error_higher_order_pred_var(pred_or_func, prog_var, inst,
|
|
arity)
|
|
% the predicate variable in a higher-order predicate
|
|
% or function call didn't have a higher-order
|
|
% predicate or function inst of the appropriate arity
|
|
; mode_error_poly_unify(prog_var, inst)
|
|
% A variable in a polymorphic unification with unknown
|
|
% type has inst other than `ground' or `any'.
|
|
; mode_error_var_is_live(prog_var)
|
|
% call to a predicate which will clobber its argument,
|
|
% but the argument is still live
|
|
; mode_error_var_has_inst(prog_var, inst, inst)
|
|
% call to a predicate with an insufficiently
|
|
% instantiated variable (for preds with one mode)
|
|
; mode_error_unify_pred(prog_var, mode_error_unify_rhs, type,
|
|
pred_or_func)
|
|
% an attempt was made to unify two higher-order
|
|
% predicate or function variables.
|
|
; mode_error_implied_mode(prog_var, inst, inst)
|
|
% a call to a predicate with an overly
|
|
% instantiated variable would use an implied
|
|
% mode of the predicate. XXX This is temporary -
|
|
% once we've implemented implied modes we can
|
|
% get rid of it.
|
|
; mode_error_no_mode_decl
|
|
% a call to a predicate for which there are
|
|
% no mode declarations (and mode inference is
|
|
% not enabled)
|
|
; mode_error_no_matching_mode(list(prog_var), list(inst))
|
|
% call to a predicate with an insufficiently
|
|
% instantiated variable (for preds with >1 mode)
|
|
; mode_error_in_callee(list(prog_var), list(inst),
|
|
pred_id, proc_id, list(mode_error_info))
|
|
% call to a predicate with initial argument insts
|
|
% for which mode inference gave a mode error
|
|
% in the callee
|
|
; mode_error_bind_var(var_lock_reason, prog_var, inst, inst)
|
|
% attempt to bind a non-local variable inside
|
|
% a negated context, or attempt to re-bind a variable
|
|
% in a parallel conjunct
|
|
; mode_error_non_local_lambda_var(prog_var, inst)
|
|
% attempt to pass a live non-ground var as a
|
|
% non-local variable to a lambda goal
|
|
; mode_error_unify_var_var(prog_var, prog_var, inst, inst)
|
|
% attempt to unify two free variables
|
|
; mode_error_unify_var_functor(prog_var, cons_id, list(prog_var),
|
|
inst, list(inst))
|
|
% attempt to unify a free var with a functor containing
|
|
% free arguments
|
|
; mode_error_unify_var_lambda(prog_var, inst, inst)
|
|
% some sort of error in
|
|
% attempt to unify a variable with lambda expression
|
|
; mode_error_conj(list(delayed_goal), schedule_culprit)
|
|
% a conjunction contains one or more unscheduleable
|
|
% goals; schedule_culprit gives the reason why
|
|
% they couldn't be scheduled.
|
|
; mode_error_final_inst(int, prog_var, inst, inst,
|
|
final_inst_error)
|
|
% one of the head variables did not have the
|
|
% expected final inst on exit from the proc
|
|
.
|
|
|
|
:- type schedule_culprit
|
|
---> goal_itself_was_impure
|
|
; goals_followed_by_impure_goal(hlds_goal)
|
|
; conj_floundered. % we've reached the end of a conjunction
|
|
% and there were still delayed goals
|
|
|
|
:- type final_inst_error
|
|
---> too_instantiated
|
|
; not_instantiated_enough
|
|
; wrongly_instantiated. % a catchall for anything that doesn't
|
|
% fit into the above two categories.
|
|
|
|
:- type mode_error_unify_rhs
|
|
---> error_at_var(prog_var)
|
|
; error_at_functor(cons_id, list(prog_var))
|
|
; error_at_lambda(list(prog_var), list(mode)).
|
|
|
|
:- type mode_error_info
|
|
---> mode_error_info(
|
|
set(prog_var), % the variables which caused the error
|
|
% (we will attempt to reschedule the goal
|
|
% if the one of these variables becomes
|
|
% more instantiated)
|
|
mode_error, % the nature of the error
|
|
prog_context, % where the error occurred
|
|
mode_context % where the error occurred
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% If there were any errors recorded in the mode_info,
|
|
% report them to the user now.
|
|
%
|
|
:- pred report_mode_errors(mode_info::in, mode_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
% print an error message describing a mode error
|
|
|
|
:- pred report_mode_error(mode_error::in, mode_info::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% report an error for a predicate with no mode declarations
|
|
% unless mode inference is enabled and the predicate is local.
|
|
|
|
:- pred maybe_report_error_no_modes(pred_id::in, pred_info::in,
|
|
module_info::in, io::di, io::uo) is det.
|
|
|
|
% initialize the mode_context.
|
|
|
|
:- pred mode_context_init(mode_context::out) is det.
|
|
|
|
% Write out the inferred `mode' declarations for a list of pred_ids.
|
|
% The bool indicates whether or not to write out determinism
|
|
% annotations on the modes (it should only be set to `yes' _after_
|
|
% determinism analysis).
|
|
|
|
:- pred write_mode_inference_messages(list(pred_id)::in, bool::in,
|
|
module_info::in, io__state::di, io__state::uo) is det.
|
|
|
|
% report an error for the case when two mode declarations
|
|
% declare indistinguishable modes
|
|
|
|
:- pred report_indistinguishable_modes_error(proc_id::in, proc_id::in,
|
|
pred_id::in, pred_info::in, module_info::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
:- pred output_mode_decl(proc_id::in, pred_info::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds__mode_info.
|
|
:- import_module check_hlds__mode_util.
|
|
:- import_module hlds__hlds_out.
|
|
:- import_module libs__globals.
|
|
:- import_module libs__options.
|
|
:- import_module parse_tree__mercury_to_mercury.
|
|
:- import_module parse_tree__prog_out.
|
|
|
|
:- import_module int, map, term_io, varset, term.
|
|
:- import_module std_util, require.
|
|
|
|
% just dispatch on the diffferent sorts of mode errors
|
|
|
|
report_mode_error(mode_error_disj(MergeContext, ErrorList), ModeInfo) -->
|
|
report_mode_error_disj(ModeInfo, MergeContext, ErrorList).
|
|
report_mode_error(mode_error_par_conj(ErrorList), ModeInfo) -->
|
|
report_mode_error_par_conj(ModeInfo, ErrorList).
|
|
report_mode_error(mode_error_higher_order_pred_var(PredOrFunc, Var, Inst,
|
|
Arity), ModeInfo) -->
|
|
report_mode_error_higher_order_pred_var(ModeInfo, PredOrFunc, Var,
|
|
Inst, Arity).
|
|
report_mode_error(mode_error_poly_unify(Var, Inst), ModeInfo) -->
|
|
report_mode_error_poly_unify(ModeInfo, Var, Inst).
|
|
report_mode_error(mode_error_var_is_live(Var), ModeInfo) -->
|
|
report_mode_error_var_is_live(ModeInfo, Var).
|
|
report_mode_error(mode_error_var_has_inst(Var, InstA, InstB), ModeInfo) -->
|
|
report_mode_error_var_has_inst(ModeInfo, Var, InstA, InstB).
|
|
report_mode_error(mode_error_unify_pred(Var, RHS, Type, PredOrFunc),
|
|
ModeInfo) -->
|
|
report_mode_error_unify_pred(ModeInfo, Var, RHS, Type, PredOrFunc).
|
|
report_mode_error(mode_error_implied_mode(Var, InstA, InstB), ModeInfo) -->
|
|
report_mode_error_implied_mode(ModeInfo, Var, InstA, InstB).
|
|
report_mode_error(mode_error_no_mode_decl, ModeInfo) -->
|
|
report_mode_error_no_mode_decl(ModeInfo).
|
|
report_mode_error(mode_error_bind_var(Reason, Var, InstA, InstB), ModeInfo) -->
|
|
report_mode_error_bind_var(ModeInfo, Reason, Var, InstA, InstB).
|
|
report_mode_error(mode_error_non_local_lambda_var(Var, Inst), ModeInfo) -->
|
|
report_mode_error_non_local_lambda_var(ModeInfo, Var, Inst).
|
|
report_mode_error(mode_error_unify_var_var(VarA, VarB, InstA, InstB),
|
|
ModeInfo) -->
|
|
report_mode_error_unify_var_var(ModeInfo, VarA, VarB, InstA, InstB).
|
|
report_mode_error(mode_error_unify_var_lambda(VarA, InstA, InstB),
|
|
ModeInfo) -->
|
|
report_mode_error_unify_var_lambda(ModeInfo, VarA, InstA, InstB).
|
|
report_mode_error(mode_error_unify_var_functor(Var, Name, Args, Inst,
|
|
ArgInsts), ModeInfo) -->
|
|
report_mode_error_unify_var_functor(ModeInfo, Var, Name, Args, Inst,
|
|
ArgInsts).
|
|
report_mode_error(mode_error_conj(Errors, Culprit), ModeInfo) -->
|
|
report_mode_error_conj(ModeInfo, Errors, Culprit).
|
|
report_mode_error(mode_error_no_matching_mode(Vars, Insts), ModeInfo) -->
|
|
report_mode_error_no_matching_mode(ModeInfo, Vars, Insts).
|
|
report_mode_error(mode_error_in_callee(Vars, Insts,
|
|
CalleePredId, CalleeProcId, CalleeErrors), ModeInfo) -->
|
|
report_mode_error_in_callee(ModeInfo, Vars, Insts,
|
|
CalleePredId, CalleeProcId, CalleeErrors).
|
|
report_mode_error(mode_error_final_inst(ArgNum, Var, VarInst, Inst, Reason),
|
|
ModeInfo) -->
|
|
report_mode_error_final_inst(ModeInfo, ArgNum, Var, VarInst, Inst,
|
|
Reason).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_conj(mode_info, list(delayed_goal), schedule_culprit,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_conj(in, in, in, di, uo) is det.
|
|
|
|
report_mode_error_conj(ModeInfo, Errors, Culprit) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
{ find_important_errors(Errors, ImportantErrors, OtherErrors) },
|
|
|
|
% if there's more than one error, and we have verbose-errors
|
|
% enabled, report them all
|
|
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
|
|
( { VerboseErrors = yes, Errors = [_, _ | _] } ->
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error in conjunction. The next "),
|
|
{ list__length(Errors, NumErrors) },
|
|
io__write_int(NumErrors),
|
|
io__write_string(" error messages\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" indicate possible causes of this error.\n"),
|
|
report_mode_error_conj_2(ImportantErrors, VarSet, Context,
|
|
ModeInfo),
|
|
report_mode_error_conj_2(OtherErrors, VarSet, Context, ModeInfo)
|
|
;
|
|
% in the normal case, only report the first error
|
|
{ ImportantErrors = [FirstImportantError | _] }
|
|
->
|
|
report_mode_error_conj_2([FirstImportantError], VarSet, Context,
|
|
ModeInfo)
|
|
;
|
|
{ OtherErrors = [FirstOtherError | _] }
|
|
->
|
|
report_mode_error_conj_2([FirstOtherError], VarSet, Context,
|
|
ModeInfo)
|
|
;
|
|
% There wasn't any error to report! This can't happen.
|
|
{ error("report_mode_error_conj") }
|
|
),
|
|
|
|
% if the goal(s) couldn't be scheduled because we couldn't
|
|
% reorder things past an impure goal, then report that.
|
|
( { Culprit = conj_floundered },
|
|
{ true } % we've already reported everything we can
|
|
; { Culprit = goal_itself_was_impure },
|
|
prog_out__write_context(Context),
|
|
io__write_string(
|
|
" The goal could not be reordered, because it was impure.\n")
|
|
; { Culprit = goals_followed_by_impure_goal(ImpureGoal) },
|
|
prog_out__write_context(Context),
|
|
io__write_string(
|
|
" The goal could not be reordered, because\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(
|
|
" it was followed by an impure goal.\n"),
|
|
{ ImpureGoal = _ - ImpureGoalInfo },
|
|
{ goal_info_get_context(ImpureGoalInfo, ImpureGoalContext) },
|
|
prog_out__write_context(ImpureGoalContext),
|
|
io__write_string(
|
|
" This is the location of the impure goal.\n")
|
|
).
|
|
|
|
:- pred find_important_errors(list(delayed_goal), list(delayed_goal),
|
|
list(delayed_goal)).
|
|
:- mode find_important_errors(in, out, out) is det.
|
|
|
|
find_important_errors([], [], []).
|
|
find_important_errors([Error | Errors], ImportantErrors, OtherErrors) :-
|
|
Error = delayed_goal(_, mode_error_info(_, ModeError, _, ModeContext),
|
|
_),
|
|
(
|
|
% an error is important unless it is a non-explicit unification,
|
|
% i.e. a head unification or a call argument unification
|
|
ModeContext = unify(unify_context(UnifyContext, _), _),
|
|
UnifyContext \= explicit,
|
|
% except that errors in lambda goals are important even
|
|
% if the unification that creates the lambda goal is
|
|
% an implicit one
|
|
ModeError \= mode_error_non_local_lambda_var(_, _)
|
|
->
|
|
ImportantErrors1 = ImportantErrors,
|
|
OtherErrors = [Error | OtherErrors1]
|
|
;
|
|
ImportantErrors = [Error | ImportantErrors1],
|
|
OtherErrors1 = OtherErrors
|
|
),
|
|
find_important_errors(Errors, ImportantErrors1, OtherErrors1).
|
|
|
|
:- pred report_mode_error_conj_2(list(delayed_goal), prog_varset, prog_context,
|
|
mode_info, io__state, io__state).
|
|
:- mode report_mode_error_conj_2(in, in, in, in, di, uo) is det.
|
|
|
|
report_mode_error_conj_2([], _, _, _) --> [].
|
|
report_mode_error_conj_2([delayed_goal(Vars, Error, Goal) | Rest],
|
|
VarSet, Context, ModeInfo) -->
|
|
globals__io_lookup_bool_option(debug_modes, Debug),
|
|
( { Debug = yes } ->
|
|
prog_out__write_context(Context),
|
|
io__write_string("Floundered goal, waiting on { "),
|
|
{ set__to_sorted_list(Vars, VarList) },
|
|
mercury_output_vars(VarList, VarSet, no),
|
|
io__write_string(" } :\n")
|
|
;
|
|
[]
|
|
),
|
|
globals__io_lookup_bool_option(very_verbose, VeryVerbose),
|
|
( { VeryVerbose = yes } ->
|
|
io__write_string("\t\t"),
|
|
{ mode_info_get_module_info(ModeInfo, ModuleInfo) },
|
|
hlds_out__write_goal(Goal, ModuleInfo, VarSet, no, 2, ".\n")
|
|
;
|
|
[]
|
|
),
|
|
{ Error = mode_error_info(_, ModeError, ErrorContext, ModeContext) },
|
|
{ mode_info_set_context(ErrorContext, ModeInfo, ModeInfo1) },
|
|
{ mode_info_set_mode_context(ModeContext, ModeInfo1, ModeInfo2) },
|
|
report_mode_error(ModeError, ModeInfo2),
|
|
report_mode_error_conj_2(Rest, VarSet, Context, ModeInfo2).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_disj(mode_info, merge_context, merge_errors,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_disj(in, in, in, di, uo) is det.
|
|
|
|
report_mode_error_disj(ModeInfo, MergeContext, ErrorList) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode mismatch in "),
|
|
write_merge_context(MergeContext),
|
|
io__write_string(".\n"),
|
|
write_merge_error_list(ErrorList, ModeInfo).
|
|
|
|
:- pred report_mode_error_par_conj(mode_info, merge_errors,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_par_conj(in, in, di, uo) is det.
|
|
|
|
report_mode_error_par_conj(ModeInfo, ErrorList) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: mutually exclusive bindings in parallel conjunction.\n"),
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" (The current implementation does not permit\n"),
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" parallel conjunctions to fail.)\n"),
|
|
write_merge_error_list(ErrorList, ModeInfo).
|
|
|
|
:- pred write_merge_error_list(merge_errors, mode_info, io__state, io__state).
|
|
:- mode write_merge_error_list(in, in, di, uo) is det.
|
|
|
|
write_merge_error_list([], _) --> [].
|
|
write_merge_error_list([Var - Insts | Errors], ModeInfo) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
prog_out__write_context(Context),
|
|
io__write_string(" `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' :: "),
|
|
output_inst_list(Insts, ModeInfo),
|
|
io__write_string(".\n"),
|
|
write_merge_error_list(Errors, ModeInfo).
|
|
|
|
:- pred write_merge_context(merge_context, io__state, io__state).
|
|
:- mode write_merge_context(in, di, uo) is det.
|
|
|
|
write_merge_context(disj) -->
|
|
io__write_string("disjunction").
|
|
write_merge_context(if_then_else) -->
|
|
io__write_string("if-then-else").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_bind_var(mode_info, var_lock_reason, prog_var,
|
|
inst, inst, io__state, io__state).
|
|
:- mode report_mode_error_bind_var(in, in, in, in, in, di, uo) is det.
|
|
|
|
report_mode_error_bind_var(ModeInfo, Reason, Var, VarInst, Inst) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" scope error: "),
|
|
( { Reason = negation },
|
|
io__write_string("attempt to bind a variable inside a negation.\n")
|
|
; { Reason = if_then_else },
|
|
io__write_string("attempt to bind a non-local variable\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" inside the condition of an if-then-else.\n")
|
|
; { Reason = lambda(PredOrFunc) },
|
|
{ hlds_out__pred_or_func_to_str(PredOrFunc, PredOrFuncS) },
|
|
io__write_string("attempt to bind a non-local variable inside\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_strings([" a ", PredOrFuncS, " lambda goal.\n"])
|
|
; { Reason = par_conj },
|
|
io__write_string("attempt to bind a non-local variable\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" inside more than one parallel conjunct.\n")
|
|
),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" Variable `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(VarInst, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" expected instantiatedness was `"),
|
|
output_inst(Inst, ModeInfo),
|
|
io__write_string("'.\n"),
|
|
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
|
|
( { VerboseErrors = yes } ->
|
|
( { Reason = negation },
|
|
io__write_string("\tA negation is only allowed to bind variables which are local to the\n"),
|
|
io__write_string("\tnegation, i.e. those which are implicitly existentially quantified\n"),
|
|
io__write_string("\tinside the scope of the negation.\n")
|
|
; { Reason = if_then_else },
|
|
io__write_string("\tThe condition of an if-then-else is only allowed\n"),
|
|
io__write_string("\tto bind variables which are local to the condition\n"),
|
|
io__write_string("\tor which occur only in the condition and the `then' part.\n")
|
|
; { Reason = lambda(_) },
|
|
io__write_string("\tA lambda goal is only allowed to bind its arguments\n"),
|
|
io__write_string("\tand variables local to the lambda expression.\n")
|
|
; { Reason = par_conj },
|
|
io__write_string("\tA nonlocal variable of a parallel conjunction may be\n"),
|
|
io__write_string("\tbound in at most one conjunct.\n")
|
|
)
|
|
;
|
|
[]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_non_local_lambda_var(mode_info, prog_var, inst,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_non_local_lambda_var(in, in, in,
|
|
di, uo) is det.
|
|
|
|
report_mode_error_non_local_lambda_var(ModeInfo, Var, VarInst) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: variable `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(VarInst, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" expected instantiatedness for non-local variables\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" of lambda goals is `ground'.\n").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_in_callee(mode_info, list(prog_var),
|
|
list(inst), pred_id, proc_id, list(mode_error_info),
|
|
io__state, io__state).
|
|
:- mode report_mode_error_in_callee(in, in, in, in, in, in,
|
|
di, uo) is det.
|
|
|
|
report_mode_error_in_callee(ModeInfo0, Vars, Insts,
|
|
CalleePredId, CalleeProcId, CalleeModeErrors) -->
|
|
{ mode_info_get_module_info(ModeInfo0, ModuleInfo) },
|
|
{ mode_info_get_context(ModeInfo0, Context) },
|
|
{ mode_info_get_varset(ModeInfo0, VarSet) },
|
|
mode_info_write_context(ModeInfo0),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: arguments `"),
|
|
mercury_output_vars(Vars, VarSet, no),
|
|
io__write_string("'\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" have insts `"),
|
|
output_inst_list(Insts, ModeInfo0),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" which does not match any of the valid modes for\n"),
|
|
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
|
|
( { VerboseErrors = yes } ->
|
|
prog_out__write_context(Context),
|
|
io__write_string(" the callee ("),
|
|
hlds_out__write_pred_id(ModuleInfo, CalleePredId),
|
|
io__write_string("),\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" because of the following error.\n")
|
|
;
|
|
prog_out__write_context(Context),
|
|
io__write_string(" the callee, because of the following error.\n")
|
|
),
|
|
( { CalleeModeErrors = [First | _] } ->
|
|
{ First = mode_error_info(_, CalleeModeError,
|
|
CalleeContext, CalleeModeContext) },
|
|
{ mode_info_set_predid(CalleePredId, ModeInfo0, ModeInfo1) },
|
|
{ mode_info_set_procid(CalleeProcId, ModeInfo1, ModeInfo2) },
|
|
{ mode_info_set_context(CalleeContext, ModeInfo2, ModeInfo3) },
|
|
{ mode_info_set_mode_context(CalleeModeContext,
|
|
ModeInfo3, ModeInfo4) },
|
|
report_mode_error(CalleeModeError, ModeInfo4)
|
|
;
|
|
{ error("report_mode_error_in_callee: no error") }
|
|
).
|
|
|
|
:- pred report_mode_error_no_matching_mode(mode_info, list(prog_var),
|
|
list(inst), io__state, io__state).
|
|
:- mode report_mode_error_no_matching_mode(in, in, in, di, uo) is det.
|
|
|
|
report_mode_error_no_matching_mode(ModeInfo, Vars, Insts) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: arguments `"),
|
|
mercury_output_vars(Vars, VarSet, no),
|
|
io__write_string("'\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" have insts `"),
|
|
output_inst_list(Insts, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" which does not match any of the modes for "),
|
|
{ mode_info_get_mode_context(ModeInfo, ModeContext) },
|
|
( { ModeContext = call(CallId, _) } ->
|
|
hlds_out__write_call_id(CallId)
|
|
;
|
|
{ error("report_mode_error_no_matching_mode: invalid context") }
|
|
),
|
|
io__write_string(".\n").
|
|
|
|
:- pred report_mode_error_higher_order_pred_var(mode_info, pred_or_func,
|
|
prog_var, inst, arity, io__state, io__state).
|
|
:- mode report_mode_error_higher_order_pred_var(in, in, in, in, in,
|
|
di, uo) is det.
|
|
|
|
report_mode_error_higher_order_pred_var(ModeInfo, PredOrFunc, Var, VarInst,
|
|
Arity) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: variable `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(VarInst, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
( { PredOrFunc = predicate },
|
|
io__write_string(
|
|
" expecting higher-order pred inst (of arity "),
|
|
io__write_int(Arity)
|
|
; { PredOrFunc = function },
|
|
io__write_string(
|
|
" expecting higher-order func inst (of arity "),
|
|
{ Arity1 = Arity - 1 },
|
|
io__write_int(Arity1)
|
|
),
|
|
io__write_string(").\n").
|
|
|
|
:- pred report_mode_error_poly_unify(mode_info, prog_var, inst,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_poly_unify(in, in, in, di, uo) is det.
|
|
|
|
report_mode_error_poly_unify(ModeInfo, Var, VarInst) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" in polymorphically-typed unification:\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: variable `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(VarInst, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(
|
|
" expected instantiatedness was `ground' or `any'.\n"),
|
|
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
|
|
( { VerboseErrors = yes } ->
|
|
io__write_string(
|
|
"\tWhen unifying two variables whose type will not be known until
|
|
\truntime, the variables must both be ground (or have inst `any').
|
|
\tUnifications of polymorphically-typed variables with partially
|
|
\tinstantiated modes are not allowed.\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred report_mode_error_var_is_live(mode_info, prog_var,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_var_is_live(in, in, di, uo) is det.
|
|
|
|
report_mode_error_var_is_live(ModeInfo, Var) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" unique-mode error: the called procedure would clobber\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" its argument, but variable `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' is still live.\n").
|
|
|
|
:- pred report_mode_error_var_has_inst(mode_info, prog_var, inst, inst,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_var_has_inst(in, in, in, in, di, uo) is det.
|
|
|
|
report_mode_error_var_has_inst(ModeInfo, Var, VarInst, Inst) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: variable `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(VarInst, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" expected instantiatedness was `"),
|
|
output_inst(Inst, ModeInfo),
|
|
io__write_string("'.\n").
|
|
|
|
:- pred report_mode_error_implied_mode(mode_info, prog_var, inst, inst,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_implied_mode(in, in, in, in, di, uo) is det.
|
|
|
|
report_mode_error_implied_mode(ModeInfo, Var, VarInst, Inst) -->
|
|
% This "error" message is really a "sorry, not implemented"
|
|
% message. We only print the message if we are actually
|
|
% going to generating code.
|
|
globals__io_lookup_bool_option(errorcheck_only, ErrorcheckOnly),
|
|
( { ErrorcheckOnly = no } ->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" sorry, implied modes not implemented.\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" Variable `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(VarInst, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" expected instantiatedness was `"),
|
|
output_inst(Inst, ModeInfo),
|
|
io__write_string("'.\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred report_mode_error_no_mode_decl(mode_info, io__state, io__state).
|
|
:- mode report_mode_error_no_mode_decl(in, di, uo) is det.
|
|
|
|
report_mode_error_no_mode_decl(ModeInfo) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" no mode declaration for called predicate.\n").
|
|
|
|
:- pred report_mode_error_unify_pred(mode_info, prog_var, mode_error_unify_rhs,
|
|
type, pred_or_func,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_unify_pred(in, in, in, in, in,
|
|
di, uo) is det.
|
|
|
|
report_mode_error_unify_pred(ModeInfo, X, RHS, Type, PredOrFunc) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
{ mode_info_get_instvarset(ModeInfo, InstVarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" In unification of `"),
|
|
mercury_output_var(X, VarSet, no),
|
|
io__write_string("' with `"),
|
|
(
|
|
{ RHS = error_at_var(Y) },
|
|
mercury_output_var(Y, VarSet, no)
|
|
;
|
|
{ RHS = error_at_functor(ConsId, ArgVars) },
|
|
{ mode_info_get_module_info(ModeInfo, ModuleInfo) },
|
|
hlds_out__write_functor_cons_id(ConsId, ArgVars, VarSet,
|
|
ModuleInfo, no)
|
|
;
|
|
{ RHS = error_at_lambda(ArgVars, ArgModes) },
|
|
io__write_string("lambda(["),
|
|
hlds_out__write_var_modes(ArgVars, ArgModes, VarSet,
|
|
InstVarSet, no),
|
|
io__write_string("] ... )")
|
|
),
|
|
io__write_string("':\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: attempt at higher-order unification.\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" Cannot unify two terms of type `"),
|
|
{ varset__init(TypeVarSet) },
|
|
mercury_output_term(Type, TypeVarSet, no),
|
|
io__write_string("'.\n"),
|
|
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
|
|
( { VerboseErrors = yes } ->
|
|
io__write_string("\tYour code is trying to test whether two "),
|
|
hlds_out__write_pred_or_func(PredOrFunc),
|
|
io__write_string("s are equal,\n"),
|
|
io__write_string("\tby unifying them. In the general case, testing equivalence\n"),
|
|
io__write_string("\tof "),
|
|
hlds_out__write_pred_or_func(PredOrFunc),
|
|
io__write_string("s is an undecidable problem,\n"),
|
|
io__write_string("\tand so this is not allowed by the Mercury mode system.\n"),
|
|
io__write_string("\tIn some cases, you can achieve the same effect by\n"),
|
|
io__write_string("\twriting an explicit universal quantification,\n"),
|
|
io__write_string("\te.g. `all [X] call(P, X) <=> call(Q, X)',"),
|
|
io__write_string(" instead of `P = Q'.\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_unify_var_var(mode_info, prog_var, prog_var,
|
|
inst, inst, io__state, io__state).
|
|
:- mode report_mode_error_unify_var_var(in, in, in, in, in, di, uo)
|
|
is det.
|
|
|
|
report_mode_error_unify_var_var(ModeInfo, X, Y, InstX, InstY) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error in unification of `"),
|
|
mercury_output_var(X, VarSet, no),
|
|
io__write_string("' and `"),
|
|
mercury_output_var(Y, VarSet, no),
|
|
io__write_string("'.\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" Variable `"),
|
|
mercury_output_var(X, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(InstX, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" variable `"),
|
|
mercury_output_var(Y, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(InstY, ModeInfo),
|
|
io__write_string("'.\n").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_unify_var_lambda(mode_info, prog_var, inst, inst,
|
|
io__state, io__state).
|
|
:- mode report_mode_error_unify_var_lambda(in, in, in, in, di, uo)
|
|
is det.
|
|
|
|
report_mode_error_unify_var_lambda(ModeInfo, X, InstX, InstY) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error in unification of `"),
|
|
mercury_output_var(X, VarSet, no),
|
|
io__write_string("' and lambda expression.\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" Variable `"),
|
|
mercury_output_var(X, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(InstX, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" lambda expression has instantiatedness `"),
|
|
output_inst(InstY, ModeInfo),
|
|
io__write_string("'.\n").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_unify_var_functor(mode_info, prog_var, cons_id,
|
|
list(prog_var), inst, list(inst), io__state, io__state).
|
|
:- mode report_mode_error_unify_var_functor(in, in, in, in, in, in,
|
|
di, uo) is det.
|
|
|
|
report_mode_error_unify_var_functor(ModeInfo, X, ConsId, Args, InstX, ArgInsts)
|
|
-->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
{ mode_info_get_module_info(ModeInfo, ModuleInfo) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error in unification of `"),
|
|
mercury_output_var(X, VarSet, no),
|
|
io__write_string("' and `"),
|
|
hlds_out__write_functor_cons_id(ConsId, Args, VarSet, ModuleInfo, no),
|
|
io__write_string("'.\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" Variable `"),
|
|
mercury_output_var(X, VarSet, no),
|
|
io__write_string("' has instantiatedness `"),
|
|
output_inst(InstX, ModeInfo),
|
|
io__write_string("',\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" term `"),
|
|
hlds_out__write_functor_cons_id(ConsId, Args, VarSet, ModuleInfo, no),
|
|
( { Args \= [] } ->
|
|
io__write_string("'\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" has instantiatedness `"),
|
|
mercury_output_cons_id(ConsId, does_not_need_brackets),
|
|
io__write_string("("),
|
|
output_inst_list(ArgInsts, ModeInfo),
|
|
io__write_string(")")
|
|
;
|
|
io__write_string("' has instantiatedness `"),
|
|
mercury_output_cons_id(ConsId, does_not_need_brackets)
|
|
),
|
|
io__write_string("'.\n").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred mode_info_write_context(mode_info, io__state, io__state).
|
|
:- mode mode_info_write_context(in, di, uo) is det.
|
|
|
|
mode_info_write_context(ModeInfo) -->
|
|
{ mode_info_get_module_info(ModeInfo, ModuleInfo) },
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_predid(ModeInfo, PredId) },
|
|
{ mode_info_get_procid(ModeInfo, ProcId) },
|
|
{ module_info_pred_proc_info(ModuleInfo, PredId, ProcId,
|
|
PredInfo, ProcInfo) },
|
|
{ PredOrFunc = pred_info_is_pred_or_func(PredInfo) },
|
|
{ pred_info_get_markers(PredInfo, PredMarkers) },
|
|
{ proc_info_declared_argmodes(ProcInfo, Modes0) },
|
|
{ strip_builtin_qualifiers_from_mode_list(Modes0, Modes) },
|
|
{ Name0 = pred_info_name(PredInfo) },
|
|
{ Name = unqualified(Name0) },
|
|
{ mode_info_get_instvarset(ModeInfo, InstVarSet) },
|
|
{ MaybeDet = no },
|
|
|
|
prog_out__write_context(Context),
|
|
io__write_string("In clause for `"),
|
|
mercury_output_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes,
|
|
MaybeDet, Context),
|
|
io__write_string("':\n"),
|
|
{ mode_info_get_mode_context(ModeInfo, ModeContext) },
|
|
write_mode_context(ModeContext, Context, PredMarkers, ModuleInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred report_mode_error_final_inst(mode_info, int, prog_var, inst, inst,
|
|
final_inst_error, io__state, io__state).
|
|
:- mode report_mode_error_final_inst(in, in, in, in, in, in,
|
|
di, uo) is det.
|
|
|
|
report_mode_error_final_inst(ModeInfo, ArgNum, Var, VarInst, Inst, Reason) -->
|
|
{ mode_info_get_context(ModeInfo, Context) },
|
|
{ mode_info_get_varset(ModeInfo, VarSet) },
|
|
mode_info_write_context(ModeInfo),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" mode error: argument "),
|
|
io__write_int(ArgNum),
|
|
( { Reason = too_instantiated } ->
|
|
io__write_string(" became too instantiated")
|
|
; { Reason = not_instantiated_enough } ->
|
|
io__write_string(" did not get sufficiently instantiated")
|
|
;
|
|
% I don't think this can happen. But just in case...
|
|
io__write_string(" had the wrong instantiatedness")
|
|
),
|
|
io__write_string(".\n"),
|
|
|
|
prog_out__write_context(Context),
|
|
io__write_string(" Final instantiatedness of `"),
|
|
mercury_output_var(Var, VarSet, no),
|
|
io__write_string("' was `"),
|
|
output_inst(VarInst, ModeInfo),
|
|
io__write_string("',\n"),
|
|
|
|
prog_out__write_context(Context),
|
|
io__write_string(" expected final instantiatedness was `"),
|
|
output_inst(Inst, ModeInfo),
|
|
io__write_string("'.\n").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
mode_context_init(uninitialized).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% XXX some parts of the mode context never get set up
|
|
|
|
:- pred write_mode_context(mode_context, prog_context, pred_markers,
|
|
module_info, io__state, io__state).
|
|
:- mode write_mode_context(in, in, in, in, di, uo) is det.
|
|
|
|
write_mode_context(uninitialized, _Context, _Markers, _ModuleInfo) -->
|
|
[].
|
|
|
|
write_mode_context(call(CallId, ArgNum), Context, Markers, _ModuleInfo) -->
|
|
prog_out__write_context(Context),
|
|
io__write_string(" in "),
|
|
hlds_out__write_call_arg_id(CallId, ArgNum, Markers),
|
|
io__write_string(":\n").
|
|
|
|
write_mode_context(unify(UnifyContext, _Side), Context, _Markers,
|
|
_ModuleInfo) -->
|
|
hlds_out__write_unify_context(UnifyContext, Context).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
maybe_report_error_no_modes(PredId, PredInfo, ModuleInfo) -->
|
|
{ pred_info_import_status(PredInfo, ImportStatus) },
|
|
( { ImportStatus = local } ->
|
|
globals__io_lookup_bool_option(infer_modes, InferModesOpt),
|
|
( { InferModesOpt = yes } ->
|
|
[]
|
|
;
|
|
io__set_exit_status(1),
|
|
{ pred_info_context(PredInfo, Context) },
|
|
prog_out__write_context(Context),
|
|
io__write_string("Error: no mode declaration for "),
|
|
hlds_out__write_pred_id(ModuleInfo, PredId),
|
|
io__write_string(".\n"),
|
|
globals__io_lookup_bool_option(verbose_errors,
|
|
VerboseErrors),
|
|
( { VerboseErrors = yes } ->
|
|
prog_out__write_context(Context),
|
|
io__write_string(
|
|
" (Use `--infer-modes' to enable mode inference.)\n")
|
|
;
|
|
[]
|
|
)
|
|
)
|
|
;
|
|
io__set_exit_status(1),
|
|
{ pred_info_context(PredInfo, Context) },
|
|
prog_out__write_context(Context),
|
|
io__write_string("Error: no mode declaration for exported\n"),
|
|
prog_out__write_context(Context),
|
|
io__write_string(" "),
|
|
hlds_out__write_pred_id(ModuleInfo, PredId),
|
|
io__write_string(".\n")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% write out the inferred `mode' declarations for a list of pred_ids.
|
|
|
|
write_mode_inference_messages([], _, _) --> [].
|
|
write_mode_inference_messages([PredId | PredIds], OutputDetism, ModuleInfo) -->
|
|
{ module_info_pred_info(ModuleInfo, PredId, PredInfo) },
|
|
{ pred_info_get_markers(PredInfo, Markers) },
|
|
( { check_marker(Markers, infer_modes) } ->
|
|
{ ProcIds = pred_info_all_procids(PredInfo) },
|
|
{ pred_info_procedures(PredInfo, Procs) },
|
|
write_mode_inference_messages_2(ProcIds, Procs, PredInfo,
|
|
OutputDetism, ModuleInfo)
|
|
;
|
|
[]
|
|
),
|
|
write_mode_inference_messages(PredIds, OutputDetism, ModuleInfo).
|
|
|
|
% write out the inferred `mode' declarations for a list of
|
|
% proc_ids
|
|
|
|
:- pred write_mode_inference_messages_2(list(proc_id), proc_table, pred_info,
|
|
bool, module_info, io__state, io__state).
|
|
:- mode write_mode_inference_messages_2(in, in, in, in, in, di, uo) is det.
|
|
|
|
write_mode_inference_messages_2([], _, _, _, _) --> [].
|
|
write_mode_inference_messages_2([ProcId | ProcIds], Procs, PredInfo,
|
|
OutputDetism, ModuleInfo) -->
|
|
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
|
|
{ map__lookup(Procs, ProcId, ProcInfo) },
|
|
(
|
|
{
|
|
% We always output `Inferred :- mode ...'
|
|
proc_info_is_valid_mode(ProcInfo)
|
|
;
|
|
% We only output `REJECTED :- mode ...'
|
|
% if --verbose-errors is enabled
|
|
VerboseErrors = yes
|
|
}
|
|
->
|
|
write_mode_inference_message(PredInfo, ProcInfo, OutputDetism,
|
|
ModuleInfo)
|
|
;
|
|
[]
|
|
),
|
|
write_mode_inference_messages_2(ProcIds, Procs, PredInfo, OutputDetism,
|
|
ModuleInfo).
|
|
|
|
% write out the inferred `mode' declaration
|
|
% for a single function or predicate.
|
|
|
|
:- pred write_mode_inference_message(pred_info, proc_info, bool,
|
|
module_info, io__state, io__state).
|
|
:- mode write_mode_inference_message(in, in, in, in, di, uo) is det.
|
|
|
|
write_mode_inference_message(PredInfo, ProcInfo, OutputDetism, ModuleInfo) -->
|
|
{ PredName = pred_info_name(PredInfo) },
|
|
{ Name = unqualified(PredName) },
|
|
{ pred_info_context(PredInfo, Context) },
|
|
{ PredArity = pred_info_arity(PredInfo) },
|
|
{ proc_info_argmodes(ProcInfo, ArgModes0) },
|
|
|
|
% We need to strip off the extra type_info arguments inserted at the
|
|
% front by polymorphism.m - we only want the last `PredArity' of them.
|
|
%
|
|
{ list__length(ArgModes0, NumArgModes) },
|
|
{ NumToDrop = NumArgModes - PredArity },
|
|
( { list__drop(NumToDrop, ArgModes0, ArgModes1) } ->
|
|
{ ArgModes2 = ArgModes1 }
|
|
;
|
|
{ error("report_pred_proc_id: list__drop failed") }
|
|
),
|
|
|
|
{ varset__init(VarSet) },
|
|
{ PredOrFunc = pred_info_is_pred_or_func(PredInfo) },
|
|
( { OutputDetism = yes } ->
|
|
{ proc_info_inferred_determinism(ProcInfo, Detism) },
|
|
{ MaybeDet0 = yes(Detism) }
|
|
;
|
|
{ MaybeDet0 = no }
|
|
),
|
|
prog_out__write_context(Context),
|
|
( { proc_info_is_valid_mode(ProcInfo) } ->
|
|
io__write_string("Inferred "),
|
|
{ ArgModes3 = ArgModes2 },
|
|
{ MaybeDet = MaybeDet0 }
|
|
;
|
|
io__write_string("REJECTED "),
|
|
% Replace the final insts with dummy insts '...',
|
|
% since they won't be valid anyway -- they are just
|
|
% the results of whatever partial inference we did
|
|
% before detecting the error.
|
|
{ mode_list_get_initial_insts(ArgModes2, ModuleInfo,
|
|
InitialInsts) },
|
|
{ DummyInst = defined_inst(user_inst(unqualified("..."), [])) },
|
|
{ list__duplicate(PredArity, DummyInst, FinalInsts) },
|
|
{ ArgModes3 = list__map(func(I - F) = (I -> F),
|
|
assoc_list__from_corresponding_lists(
|
|
InitialInsts, FinalInsts)) },
|
|
% Likewise delete the determinism.
|
|
{ MaybeDet = no }
|
|
),
|
|
{ strip_builtin_qualifiers_from_mode_list(ArgModes3, ArgModes) },
|
|
( { PredOrFunc = predicate },
|
|
mercury_output_pred_mode_decl(VarSet, Name, ArgModes,
|
|
MaybeDet, Context)
|
|
; { PredOrFunc = function },
|
|
{ pred_args_to_func_args(ArgModes, FuncArgModes, RetMode) },
|
|
mercury_output_func_mode_decl(VarSet, Name, FuncArgModes,
|
|
RetMode, MaybeDet, Context)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% If there were any errors recorded in the mode_info,
|
|
% report them to the user now.
|
|
|
|
report_mode_errors(!ModeInfo, !IO) :-
|
|
mode_info_get_errors(!.ModeInfo, Errors),
|
|
( Errors = [FirstError | _] -> % XXX Why do we only report the first?
|
|
FirstError = mode_error_info(_, ModeError, Context,
|
|
ModeContext),
|
|
mode_info_set_context(Context, !ModeInfo),
|
|
mode_info_set_mode_context(ModeContext, !ModeInfo),
|
|
report_mode_error(ModeError, !.ModeInfo, !IO)
|
|
;
|
|
true
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred output_inst((inst), mode_info, io__state, io__state).
|
|
:- mode output_inst(in, in, di, uo) is det.
|
|
|
|
output_inst(Inst0, ModeInfo) -->
|
|
{ strip_builtin_qualifiers_from_inst(Inst0, Inst) },
|
|
{ mode_info_get_instvarset(ModeInfo, InstVarSet) },
|
|
{ mode_info_get_module_info(ModeInfo, ModuleInfo) },
|
|
mercury_output_expanded_inst(Inst, InstVarSet, ModuleInfo).
|
|
|
|
:- pred output_inst_list(list(inst), mode_info, io__state, io__state).
|
|
:- mode output_inst_list(in, in, di, uo) is det.
|
|
|
|
output_inst_list([], _) --> [].
|
|
output_inst_list([Inst | Insts], ModeInfo) -->
|
|
output_inst(Inst, ModeInfo),
|
|
( { Insts = [] } ->
|
|
[]
|
|
;
|
|
io__write_string(", "),
|
|
output_inst_list(Insts, ModeInfo)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
report_indistinguishable_modes_error(OldProcId, NewProcId,
|
|
PredId, PredInfo, ModuleInfo) -->
|
|
|
|
io__set_exit_status(1),
|
|
|
|
{ pred_info_procedures(PredInfo, Procs) },
|
|
{ map__lookup(Procs, OldProcId, OldProcInfo) },
|
|
{ map__lookup(Procs, NewProcId, NewProcInfo) },
|
|
{ proc_info_context(OldProcInfo, OldContext) },
|
|
{ proc_info_context(NewProcInfo, NewContext) },
|
|
|
|
prog_out__write_context(NewContext),
|
|
io__write_string("In mode declarations for "),
|
|
hlds_out__write_pred_id(ModuleInfo, PredId),
|
|
io__write_string(":\n"),
|
|
|
|
prog_out__write_context(NewContext),
|
|
io__write_string(" error: duplicate mode declaration.\n"),
|
|
|
|
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
|
|
( { VerboseErrors = yes } ->
|
|
prog_out__write_context(NewContext),
|
|
io__write_string(" Modes `"),
|
|
output_mode_decl(OldProcId, PredInfo),
|
|
io__write_string("'\n"),
|
|
|
|
prog_out__write_context(NewContext),
|
|
io__write_string(" and `"),
|
|
output_mode_decl(NewProcId, PredInfo),
|
|
io__write_string("'\n"),
|
|
|
|
prog_out__write_context(NewContext),
|
|
io__write_string(" are indistinguishable.\n")
|
|
;
|
|
[]
|
|
),
|
|
|
|
prog_out__write_context(OldContext),
|
|
io__write_string(
|
|
" Here is the conflicting mode declaration.\n").
|
|
|
|
output_mode_decl(ProcId, PredInfo, !IO) :-
|
|
PredOrFunc = pred_info_is_pred_or_func(PredInfo),
|
|
Name0 = pred_info_name(PredInfo),
|
|
Name = unqualified(Name0),
|
|
pred_info_procedures(PredInfo, Procs),
|
|
map__lookup(Procs, ProcId, ProcInfo),
|
|
proc_info_declared_argmodes(ProcInfo, Modes0),
|
|
proc_info_declared_determinism(ProcInfo, MaybeDet),
|
|
proc_info_context(ProcInfo, Context),
|
|
varset__init(InstVarSet),
|
|
strip_builtin_qualifiers_from_mode_list(Modes0, Modes),
|
|
mercury_output_mode_subdecl(PredOrFunc, InstVarSet, Name, Modes,
|
|
MaybeDet, Context, !IO).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|