mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 09:23:44 +00:00
The new --warn-unneeded-initial-statevar option asks the compiler
to warn about code such as
pred_a(!.X, ...) :-
... code that uses !.X, but does not update it ...
In this case, the preferred fix is to just replace all occurrences
of !.X with X.
The new --warn-unneeded-final-statevar option asks the compiler
to warn about code such as
pred_a(!X, ...) :-
... code that maybe uses !.X, but does not update it ...
In this case, the preferred fix also involves replacing all occurrences
of !.X with X, but it also involves either deleting the argument
containing !:X (the best option), or, if there is some reason why
the predicate's signature must stay unchanged, to replace !:X with X as well.
And if the clause body does not actually refer to either !.X or !:X, then
*both* arguments represented by !X should be deleted.
The first option is a style warning; the second option, due to the
signature change it may call for, is a non-style warning.
Both options have a version whose name adds a "-lambda" suffix, and which
does the same warnings for the heads of lambda expressions, not clauses.
Note that several of the modules below, including some that help to implement
the warnings, also contain code changes that result from *acting* on
the new warnings, e.g. by deleting unneeded statevar arguments.
Other, similar changes will also come after this diff is committed.
compiler/options.m:
doc/user_guide.texi:
Document the new options.
compiler/state_var.m:
Gather the information needed to decide what code merits the new warnings.
Do so in three stages:
- when processing the head of a clause or of a lambda expression,
- when processing the body goal of that clause or lambda expression,
- when finishing up the processing of the clause or lambda expression.
Add a predicate to generate the warnings for lambda expressions.
Do not generate the warnings for clauses. This is because whether or not
we want to warn about state vars in some clauses depends on the properties
of *other* clauses of the same predicate, and state_var.m has access
to only one clause at a time. Instead,
- return the info needed by the warning-generating code in pre_typecheck.m
(one of the first passes we execute after adding all clauses
to the HLDS), and
- we export some functionality for use by that code.
Switch to a convention for naming the program variables corresponding
to the middle (non-initial, non-final) versions of state variables
whose output is affected by changes in the code of the clause body goal
only if they involve that specific state variable.
Give some predicates more descriptive names.
compiler/make_hlds.m:
Make state_var.m and its new functionality visible from outside
the make_hlds package.
compiler/add_clause.m:
Record the information gathered by state_var.m in each clause.
compiler/hlds_clauses.m:
Add a slot to each clause for this information.
Give some predicates more descriptive names.
compiler/headvar_names.m:
Use the contents of the new slots to detect whether any clauses
have unused state vars, and if so, return the chosen consensus names
of the head vars to the code of pre_typecheck.m, which uses this info
as part of the implementation of the new warnings.
compiler/pre_typecheck.m:
Implement the new warnings.
compiler/mercury_compile_front_end.m:
Record the warnings that pre_typecheck.m can now return.
compiler/error_spec.m:
compiler/write_error_spec.m:
Add unsigned versions of the format pieces involving ints, for use
by the new code in pre_typecheck.m, and implement them.
compiler/hlds_out_util.m:
compiler/maybe_util.m:
Move two related types from hlds_out_util.m to maybe_util.m,
in order to allow pre_typecheck.m to use one of them.
compiler/hlds_args.m:
Add a new utility function for use by the new code above.
compiler/foreign.m:
Act on the new warnings by deleting the long-unused predicates
being warned about.
compiler/post_typecheck.m:
Speed up this traversal. (I originally thought to implement
the new warnings in this pass.)
compiler/add_foreign_proc.m:
compiler/add_pragma.m:
compiler/add_pragma_tabling.m:
compiler/add_pragma_type_spec.m:
compiler/add_pred.m:
compiler/add_type.m:
compiler/build_mode_constraints.m:
compiler/call_gen.m:
compiler/check_typeclass.m:
compiler/clause_to_proc.m:
compiler/code_loc_dep.m:
compiler/delay_info.m:
compiler/delay_partial_inst.m:
compiler/dense_switch.m:
compiler/det_check_goal.m:
compiler/det_infer_goal.m:
compiler/disj_gen.m:
compiler/du_type_layout.m:
compiler/format_call.m:
compiler/goal_expr_to_goal.m:
compiler/hlds_dependency_graph.m:
compiler/hlds_out_pred.m:
compiler/hlds_pred.m:
compiler/hlds_rtti.m:
compiler/inst_merge.m:
compiler/instance_method_clauses.m:
compiler/intermod.m:
compiler/interval.m:
compiler/ite_gen.m:
compiler/lookup_switch.m:
compiler/make_hlds_passes.m:
compiler/mark_tail_calls.m:
compiler/mercury_compile_llds_back_end.m:
compiler/mode_errors.m:
compiler/parse_string_format.m:
compiler/passes_aux.m:
compiler/polymorphism.m:
compiler/polymorphism_info.m:
compiler/polymorphism_type_info.m:
compiler/pragma_c_gen.m:
compiler/prop_mode_constraints.m:
compiler/purity.m:
compiler/quantification.m:
compiler/simplify_goal_call.m:
compiler/simplify_goal_conj.m:
compiler/string_switch.m:
compiler/superhomogeneous.m:
compiler/switch_gen.m:
compiler/tag_switch.m:
compiler/type_constraints.m:
compiler/typecheck.m:
compiler/typecheck_clauses.m:
compiler/typecheck_coerce.m:
compiler/typecheck_error_unify.m:
compiler/unify_gen_deconstruct.m:
compiler/unify_proc.m:
compiler/var_origins.m:
Conform to the changes above, and/or act on the new warnings.
browser/diff.m:
library/bit_buffer.m:
library/getopt.m:
library/getopt_io.m:
library/io.error_util.m:
library/io.file.m:
library/mercury_term_lexer.m:
library/parsing_utils.m:
library/pretty_printer.m:
library/robdd.m:
library/rtti_implementation.m:
library/string.builder.m:
library/string.parse_runtime.m:
mdbcomp/feedback.m:
Act on the new warnings.
tests/hard_coded/sv_nested_closures.m:
Change this test's code to avoid the new warnings, since
(if --halt-at-warn is ever enabled) the warnings would interfere
with its job .
tests/invalid/bug197.err_exp:
tests/invalid/bug487.err_exp:
tests/invalid/nullary_ho_func_error.err_exp:
tests/invalid/try_detism.err_exp:
tests/warnings/singleton_test_state_var.err_exp:
Expect variable names for the middle versions of state vars
using the new naming scheme.
430 lines
18 KiB
Mathematica
430 lines
18 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1995-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-2025 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: polymorphism.m.
|
|
% Main authors: fjh and zs.
|
|
%
|
|
% This module and its subcontractors implement a pass over the HLDS.
|
|
% This pass does a syntactic transformation to implement both parametric
|
|
% and ad-hoc (typeclass-based) polymorphism, by passing extra `type_info'
|
|
% and `typeclass_info' arguments between predicates and functions.
|
|
% These arguments are structures that contain, amongst other things,
|
|
% higher order predicate terms for the polymorphic procedures or methods.
|
|
%
|
|
% See notes/type_class_transformation.html for a description of the
|
|
% transformation and data structures used to implement type classes.
|
|
%
|
|
% XXX The way the code in this pass handles existential type classes
|
|
% and type class constraints is a bit ad hoc, in general; there are
|
|
% definitely parts of this code (marked with XXXs) that could do with
|
|
% a rewrite to make it more consistent, and hence more maintainable.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Transformation of polymorphic code:
|
|
%
|
|
% Every polymorphic predicate is transformed so that it takes one additional
|
|
% argument for every type variable in the predicate's type declaration.
|
|
% The argument gives information about the type, including higher order
|
|
% predicate variables for each of the builtin polymorphic operations
|
|
% (currently unify/2, compare/3).
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Example of transformation:
|
|
%
|
|
% Take the following code as an example, ignoring the requirement for
|
|
% superhomogeneous form for clarity:
|
|
%
|
|
% :- pred p(T1).
|
|
% :- pred q(T2).
|
|
% :- pred r(T3).
|
|
%
|
|
% p(X) :- q([X]), r(0).
|
|
%
|
|
% We add an extra argument for each type variable:
|
|
%
|
|
% :- pred p(type_info(T1), T1).
|
|
% :- pred q(type_info(T2), T2).
|
|
% :- pred r(type_info(T3), T3).
|
|
%
|
|
% We transform the body of p to this:
|
|
%
|
|
% p(TypeInfoT1, X) :-
|
|
% TypeCtorInfoT2 = type_ctor_info(list/1),
|
|
% TypeInfoT2 = type_info(TypeCtorInfoT2, TypeInfoT1),
|
|
% q(TypeInfoT2, [X]),
|
|
% TypeInfoT3 = type_ctor_info(int/0),
|
|
% r(TypeInfoT3, 0).
|
|
%
|
|
% Note that type_ctor_infos are actually generated as references to a
|
|
% single shared type_ctor_info.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Transformation of code using existentially quantified types:
|
|
%
|
|
% The transformation for existential types is similar to the transformation
|
|
% for universally quantified types, except that the type_infos and
|
|
% type_class_infos have mode `out' rather than mode `in'.
|
|
%
|
|
% The argument passing convention is that the new parameters
|
|
% introduced by this pass are placed in the following order:
|
|
%
|
|
% First the type_infos for unconstrained universally quantified type
|
|
% variables, in the order that the type variables first appear in the
|
|
% argument types;
|
|
%
|
|
% then the type_infos for unconstrained existentially quantified type
|
|
% variables, in the order that the type variables first appear in the
|
|
% argument types;
|
|
%
|
|
% then the typeclass_infos for universally quantified constraints,
|
|
% in the order that the constraints appear in the class context;
|
|
%
|
|
% then the typeclass_infos for existentially quantified constraints,
|
|
% in the order that the constraints appear in the class context;
|
|
%
|
|
% and finally the original arguments of the predicate.
|
|
%
|
|
% Bear in mind that for the purposes of this (and most other) calculations,
|
|
% the return parameter of a function counts as the _last_ argument.
|
|
%
|
|
% The convention for class method implementations is slightly different
|
|
% to match the order that the type_infos and typeclass_infos are passed
|
|
% in by do_call_class_method (in runtime/mercury_ho_call.c):
|
|
%
|
|
% First the type_infos for the unconstrained type variables in the
|
|
% instance declaration, in the order that the type variables first appear
|
|
% in the instance arguments;
|
|
%
|
|
% then the typeclass_infos for the class constraints on the instance
|
|
% declaration, in the order that the constraints appear in the declaration;
|
|
%
|
|
% then the remainder of the arguments as above.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds.polymorphism.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module hlds.hlds_pred.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.error_spec.
|
|
:- import_module parse_tree.maybe_error.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Run the polymorphism pass over the whole HLDS.
|
|
%
|
|
:- pred polymorphism_process_module(io.text_output_stream::in,
|
|
module_info::in, module_info::out, list(pred_id)::out,
|
|
maybe_safe_to_continue::out, list(error_spec)::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Run the polymorphism pass over a single pred. This is used to transform
|
|
% clauses introduced by unify_proc.m for complicated unification predicates
|
|
% for types for which unification predicates are generated lazily.
|
|
%
|
|
% This predicate should be used with caution. polymorphism.m expects that
|
|
% the argument types of called predicates have not been transformed yet.
|
|
% This predicate will not work correctly after the original pass of
|
|
% polymorphism has been run if the predicate to be processed calls
|
|
% any polymorphic predicates which require type_infos or typeclass_infos
|
|
% to be added to the argument list.
|
|
%
|
|
% For backwards compatibility, this predicate also does the tasks
|
|
% that older versions of the polymorphism pass used to do: copying
|
|
% goals from clauses to procedures, and doing the post-copying parts
|
|
% of the polymorphism transformation.
|
|
%
|
|
:- pred polymorphism_process_generated_pred(pred_id::in,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.clause_to_proc.
|
|
:- import_module check_hlds.introduce_exists_casts.
|
|
:- import_module check_hlds.polymorphism_clause.
|
|
:- import_module check_hlds.polymorphism_info.
|
|
:- import_module hlds.const_struct.
|
|
:- import_module hlds.hlds_args.
|
|
:- import_module hlds.hlds_clauses.
|
|
:- import_module hlds.passes_aux.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.program_representation.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_data_pragma.
|
|
:- import_module parse_tree.prog_type_unify.
|
|
:- import_module parse_tree.var_table.
|
|
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module one_or_more.
|
|
:- import_module require.
|
|
:- import_module term_context.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% This whole section just traverses the module structure.
|
|
% We do two passes, the first to fix up the clauses_info and proc_infos
|
|
% (and in fact everything except the pred_info argtypes), the second to fix up
|
|
% the pred_info argtypes. The reason we need two passes is that the first pass
|
|
% looks at the argtypes of the called predicates, and so we need to make
|
|
% sure we don't muck them up before we have finished the first pass.
|
|
%
|
|
|
|
polymorphism_process_module(ProgressStream, !ModuleInfo, ExistsCastPredIds,
|
|
SafeToContinue, Specs) :-
|
|
module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0),
|
|
map.keys(PredIdTable0, PredIds0),
|
|
list.foldl3(maybe_polymorphism_process_pred(ProgressStream), PredIds0,
|
|
safe_to_continue, SafeToContinue, [], Specs, !ModuleInfo),
|
|
module_info_get_pred_id_table(!.ModuleInfo, PredIdTable1),
|
|
map.keys(PredIdTable1, PredIds1),
|
|
list.foldl2(polymorphism_update_arg_types(yes(ProgressStream)), PredIds1,
|
|
[], ExistsCastPredIds, !ModuleInfo).
|
|
|
|
:- pred maybe_polymorphism_process_pred(io.text_output_stream::in, pred_id::in,
|
|
maybe_safe_to_continue::in, maybe_safe_to_continue::out,
|
|
list(error_spec)::in, list(error_spec)::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
maybe_polymorphism_process_pred(ProgressStream, PredId, !SafeToContinue,
|
|
!Specs, !ModuleInfo) :-
|
|
module_info_pred_info(!.ModuleInfo, PredId, PredInfo),
|
|
( if
|
|
PredModule = pred_info_module(PredInfo),
|
|
PredName = pred_info_name(PredInfo),
|
|
pred_info_get_orig_arity(PredInfo, pred_form_arity(PredFormArityInt)),
|
|
no_type_info_builtin(PredModule, PredName, PredFormArityInt)
|
|
then
|
|
true
|
|
else
|
|
polymorphism_process_pred_msg(ProgressStream, PredId, !SafeToContinue,
|
|
!Specs, !ModuleInfo)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred polymorphism_process_pred_msg(io.text_output_stream::in, pred_id::in,
|
|
maybe_safe_to_continue::in, maybe_safe_to_continue::out,
|
|
list(error_spec)::in, list(error_spec)::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
polymorphism_process_pred_msg(ProgressStream, PredId,
|
|
!SafeToContinue, !Specs, !ModuleInfo) :-
|
|
% Since polymorphism transforms not just the procedures defined
|
|
% in the module being compiled, but also all the procedures in
|
|
% all the imported modules, this message can be printed A LOT,
|
|
% even though it is almost never of interest.
|
|
% That is why we enable it only when requested.
|
|
trace [compiletime(flag("poly_msgs")), io(!IO)] (
|
|
maybe_write_pred_progress_message(ProgressStream, !.ModuleInfo,
|
|
"Transforming polymorphism for", PredId, !IO)
|
|
),
|
|
polymorphism_process_pred(PredId, PredSafeToContinue, !Specs, !ModuleInfo),
|
|
(
|
|
PredSafeToContinue = safe_to_continue
|
|
;
|
|
PredSafeToContinue = unsafe_to_continue,
|
|
!:SafeToContinue = unsafe_to_continue
|
|
).
|
|
|
|
polymorphism_process_generated_pred(PredId, !ModuleInfo) :-
|
|
polymorphism_process_pred(PredId, SafeToContinue, [], Specs, !ModuleInfo),
|
|
expect(unify(Specs, []), $pred,
|
|
"generated pred has errors"),
|
|
expect(unify(SafeToContinue, safe_to_continue), $pred,
|
|
"generated pred has errors"),
|
|
polymorphism_update_arg_types(maybe.no, PredId, [], ExistsPredIds,
|
|
!ModuleInfo),
|
|
copy_clauses_to_procs_for_pred_in_module_info(PredId, !ModuleInfo),
|
|
list.foldl(introduce_exists_casts_poly, ExistsPredIds, !ModuleInfo).
|
|
|
|
:- pred polymorphism_process_pred(pred_id::in, maybe_safe_to_continue::out,
|
|
list(error_spec)::in, list(error_spec)::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
polymorphism_process_pred(PredId, SafeToContinue, !Specs, !ModuleInfo) :-
|
|
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
|
|
% Replace 99999 with the id of the predicate you want to debug.
|
|
( if pred_id_to_int(PredId) = 99999 then
|
|
poly_info_set_selected_pred(is_selected_pred, !IO)
|
|
else
|
|
true
|
|
)
|
|
),
|
|
|
|
% Run the polymorphism pass over the clauses_info, updating the headvars,
|
|
% goals, varsets, types, etc., and computing some information in the
|
|
% poly_info.
|
|
module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
|
|
pred_info_get_clauses_info(PredInfo0, ClausesInfo0),
|
|
init_poly_info(!.ModuleInfo, PredInfo0, ClausesInfo0, PolyInfo0),
|
|
polymorphism_process_clause_info(PredInfo0, ExtraArgModes,
|
|
ClausesInfo0, ClausesInfo, PolyInfo0, PolyInfo),
|
|
poly_info_get_module_info(PolyInfo, !:ModuleInfo),
|
|
poly_info_get_const_struct_db(PolyInfo, ConstStructDb),
|
|
module_info_set_const_struct_db(ConstStructDb, !ModuleInfo),
|
|
|
|
poly_info_get_typevarset(PolyInfo, TypeVarSet),
|
|
pred_info_set_typevarset(TypeVarSet, PredInfo0, PredInfo1),
|
|
pred_info_set_clauses_info(ClausesInfo, PredInfo1, PredInfo2),
|
|
|
|
poly_info_get_errors(PolyInfo, PredSpecs),
|
|
(
|
|
PredSpecs = [],
|
|
SafeToContinue = safe_to_continue
|
|
;
|
|
PredSpecs = [_ | _],
|
|
SafeToContinue = unsafe_to_continue,
|
|
!:Specs = PredSpecs ++ !.Specs
|
|
),
|
|
|
|
% Do a pass over the proc_infos, updating all the argmodes with
|
|
% modes for the extra arguments.
|
|
pred_info_get_proc_table(PredInfo2, ProcMap0),
|
|
map.map_values_only(add_extra_arg_modes_to_proc(ExtraArgModes),
|
|
ProcMap0, ProcMap),
|
|
pred_info_set_proc_table(ProcMap, PredInfo2, PredInfo),
|
|
module_info_set_pred_info(PredId, PredInfo, !ModuleInfo),
|
|
|
|
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
|
|
poly_info_set_selected_pred(is_not_selected_pred, !IO)
|
|
).
|
|
|
|
:- pred add_extra_arg_modes_to_proc(poly_arg_vector(mer_mode)::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
add_extra_arg_modes_to_proc(ExtraArgModes, !ProcInfo) :-
|
|
% Add the ExtraArgModes to the proc_info argmodes.
|
|
% XXX ARGVEC - revisit this when the proc_info uses proc_arg_vectors.
|
|
proc_info_get_argmodes(!.ProcInfo, ArgModes1),
|
|
ExtraArgModesList = poly_arg_vector_to_list(ExtraArgModes),
|
|
ArgModes = ExtraArgModesList ++ ArgModes1,
|
|
proc_info_set_argmodes(ArgModes, !ProcInfo).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred polymorphism_update_arg_types(maybe(io.text_output_stream)::in,
|
|
pred_id::in, list(pred_id)::in, list(pred_id)::out,
|
|
module_info::in, module_info::out) is det.
|
|
|
|
polymorphism_update_arg_types(MaybeProgressStream, PredId,
|
|
!ExistsCastPredIds, !ModuleInfo) :-
|
|
% Recompute the arg types by finding the headvars and the var->type mapping
|
|
% (from the clauses_info) and applying the type mapping to the extra
|
|
% headvars to get the new arg types. Note that we are careful to only apply
|
|
% the mapping to the extra head vars, not to the originals, because
|
|
% otherwise we would stuff up the arg types for unification predicates for
|
|
% equivalence types.
|
|
|
|
% Since polymorphism transforms not just the procedures defined
|
|
% in the module being compiled, but also all the procedures in
|
|
% all the imported modules, this message can be printed A LOT,
|
|
% even though it is almost never of interest.
|
|
% That is why we enable it only when requested.
|
|
trace [compiletime(flag("poly_msgs")), io(!IO)] (
|
|
(
|
|
MaybeProgressStream = no
|
|
;
|
|
MaybeProgressStream = yes(ProgressStream),
|
|
maybe_write_pred_progress_message(ProgressStream, !.ModuleInfo,
|
|
"Update polymorphism arg types for", PredId, !IO)
|
|
)
|
|
),
|
|
|
|
module_info_pred_info(!.ModuleInfo, PredId, PredInfo0),
|
|
pred_info_get_clauses_info(PredInfo0, ClausesInfo0),
|
|
clauses_info_get_var_table(ClausesInfo0, VarTable0),
|
|
clauses_info_get_arg_vector(ClausesInfo0, HeadVars),
|
|
proc_arg_vector_partition_poly_args(HeadVars, ExtraHeadVarList,
|
|
OldHeadVarList),
|
|
% We need ExistQVars whether or not ExtraHeadVarList is empty or not.
|
|
pred_info_get_arg_types(PredInfo0, TypeVarSet, ExistQVars, ArgTypes0),
|
|
list.length(ExtraHeadVarList, NumExtraHeadVars),
|
|
(
|
|
ExtraHeadVarList = [],
|
|
PredInfo2 = PredInfo0
|
|
;
|
|
ExtraHeadVarList = [_ | _],
|
|
lookup_var_types(VarTable0, ExtraHeadVarList, ExtraArgTypes),
|
|
ArgTypes = ExtraArgTypes ++ ArgTypes0,
|
|
pred_info_set_arg_types(TypeVarSet, ExistQVars, ArgTypes,
|
|
PredInfo0, PredInfo1),
|
|
pred_info_get_format_call_info(PredInfo1, MaybeFormatCall1),
|
|
(
|
|
MaybeFormatCall1 = no,
|
|
PredInfo2 = PredInfo1
|
|
;
|
|
MaybeFormatCall1 = yes(FormatCall1),
|
|
FormatCall1 = format_call_info(Context, OoMFormatStrsValues1),
|
|
% Update the argument numbers in the format_call field
|
|
% to account for the new arguments we just added at the front
|
|
% of the argument list.
|
|
one_or_more.map(increment_arg_nums(NumExtraHeadVars),
|
|
OoMFormatStrsValues1, OoMFormatStrsValues2),
|
|
FormatCall2 = format_call_info(Context, OoMFormatStrsValues2),
|
|
MaybeFormatCall2 = yes(FormatCall2),
|
|
pred_info_set_format_call_info(MaybeFormatCall2,
|
|
PredInfo1, PredInfo2)
|
|
)
|
|
),
|
|
|
|
% If the clauses bind some existentially quantified type variables,
|
|
% introduce exists_casts goals for affected head variables, including
|
|
% the new type_info and typeclass_info arguments. Make sure the types
|
|
% of the internal versions of type_infos for those type variables
|
|
% in the variable types map are as specific as possible.
|
|
|
|
( if
|
|
ExistQVars = [_ | _],
|
|
% This can fail for unification procedures of equivalence types.
|
|
lookup_var_types(VarTable0, OldHeadVarList, OldHeadVarTypes),
|
|
type_list_subsumes(ArgTypes0, OldHeadVarTypes, Subn),
|
|
not map.is_empty(Subn)
|
|
then
|
|
pred_info_set_existq_tvar_binding(Subn, PredInfo2, PredInfo3),
|
|
!:ExistsCastPredIds = [PredId | !.ExistsCastPredIds]
|
|
else
|
|
PredInfo3 = PredInfo2
|
|
),
|
|
|
|
pred_info_set_polymorphism_added_args(NumExtraHeadVars,
|
|
PredInfo3, PredInfo),
|
|
module_info_set_pred_info(PredId, PredInfo, !ModuleInfo).
|
|
|
|
:- pred increment_arg_nums(int::in,
|
|
format_string_values::in, format_string_values::out) is det.
|
|
|
|
increment_arg_nums(Inc, FSV0, FSV) :-
|
|
FSV0 = format_string_values(OrigFormatStrArgNum, OrigValuesListArgNum,
|
|
CurFormatStrArgNum, CurValuesListArgNum),
|
|
FSV = format_string_values(OrigFormatStrArgNum, OrigValuesListArgNum,
|
|
CurFormatStrArgNum + Inc, CurValuesListArgNum + Inc).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module check_hlds.polymorphism.
|
|
%---------------------------------------------------------------------------%
|