Files
mercury/compiler/polymorphism_info.m
Zoltan Somogyi f70b5d6de7 Implement options to warn about unused state vars.
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.
2025-05-18 06:43:24 +10:00

825 lines
31 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1995-2012 The University of Melbourne.
% Copyright (C) 2014-2015, 2021-2022, 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_info.m.
% Main authors: fjh and zs (when this code was in polymorphism.m).
%
% This module defines the poly_info structure used by polymorphism.m.
%
%---------------------------------------------------------------------------%
:- module check_hlds.polymorphism_info.
:- interface.
:- import_module hlds.
:- import_module hlds.const_struct.
:- import_module hlds.hlds_class.
:- import_module hlds.hlds_clauses.
:- import_module hlds.hlds_goal.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
:- import_module hlds.hlds_rtti.
:- import_module parse_tree.
:- import_module parse_tree.error_spec.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.var_table.
:- import_module assoc_list.
:- import_module io.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module pair.
%---------------------------------------------------------------------------%
:- type const_or_var_arg
---> cova_const(const_struct_arg)
; cova_var(prog_var).
:- type type_info_var_map ==
map(type_ctor,
map(list(mer_type), pair(prog_var, maybe(const_struct_arg)))).
:- type typeclass_info_map_entry
---> typeclass_info_map_entry(
% The cons_id representing the base_typeclass_info.
cons_id,
% Maps the arguments of the typeclass_info_cell_constructor
% after the base_typeclass_info to the variable that holds the
% typeclass_info for that cell.
map(list(const_or_var_arg),
pair(prog_var, maybe(const_struct_arg)))
).
:- type typeclass_info_map ==
map(class_name, map(list(mer_type), typeclass_info_map_entry)).
:- type int_const_map == map(int, prog_var).
% If the value that can be a constant structure argument is currently
% available in a variable, give the id of that variable.
%
:- type const_struct_var_map == map(const_struct_arg, prog_var).
%---------------------------------------------------------------------------%
:- type poly_info.
% Init_poly_info initializes a poly_info from a pred_info and clauses_info.
% (See also create_poly_info.)
%
:- pred init_poly_info(module_info::in, pred_info::in, clauses_info::in,
poly_info::out) is det.
% Extract some fields from a pred_info and proc_info and use them to
% create a poly_info, for use by the polymorphism transformation.
%
:- pred create_poly_info(module_info::in, pred_info::in,
proc_info::in, poly_info::out) is det.
% Update the fields in a pred_info and proc_info with
% the values in a poly_info.
%
:- pred poly_info_extract(poly_info::in, list(error_spec)::out,
pred_info::in, pred_info::out, proc_info::in, proc_info::out,
module_info::out) is det.
%---------------------------------------------------------------------------%
:- type maybe_must_requantify
---> no_must_requantify
; must_requantify.
:- pred poly_info_get_module_info(poly_info::in,
module_info::out) is det.
:- pred poly_info_get_var_table(poly_info::in,
var_table::out) is det.
:- pred poly_info_get_rtti_varmaps(poly_info::in,
rtti_varmaps::out) is det.
:- pred poly_info_get_typevarset(poly_info::in,
tvarset::out) is det.
:- pred poly_info_get_tvar_kind_map(poly_info::in,
tvar_kind_map::out) is det.
:- pred poly_info_get_proof_map(poly_info::in,
constraint_proof_map::out) is det.
:- pred poly_info_get_constraint_map(poly_info::in,
constraint_map::out) is det.
:- pred poly_info_get_type_info_var_map(poly_info::in,
type_info_var_map::out) is det.
:- pred poly_info_get_typeclass_info_map(poly_info::in,
typeclass_info_map::out) is det.
:- pred poly_info_get_int_const_map(poly_info::in,
int_const_map::out) is det.
:- pred poly_info_get_const_struct_var_map(poly_info::in,
const_struct_var_map::out) is det.
:- pred poly_info_get_num_reuses(poly_info::in,
int::out) is det.
:- pred poly_info_get_const_struct_db(poly_info::in,
const_struct_db::out) is det.
:- pred poly_info_get_defined_where(poly_info::in,
defined_where::out) is det.
:- pred poly_info_get_must_requantify(poly_info::in,
maybe_must_requantify::out) is det.
:- pred poly_info_get_errors(poly_info::in,
list(error_spec)::out) is det.
:- pred poly_info_set_var_table(var_table::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_var_table_rtti(var_table::in, rtti_varmaps::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_rtti_varmaps(rtti_varmaps::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_typevarset(tvarset::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_proof_map(constraint_proof_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_type_info_var_map(type_info_var_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_typeclass_info_map(typeclass_info_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_int_const_map(int_const_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_const_struct_var_map(const_struct_var_map::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_num_reuses(int::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_const_struct_db(const_struct_db::in,
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_must_requantify(
poly_info::in, poly_info::out) is det.
:- pred poly_info_set_errors(list(error_spec)::in,
poly_info::in, poly_info::out) is det.
%---------------------------------------------------------------------------%
:- type cache_maps
---> cache_maps(
cm_snapshot_num :: int,
cm_type_info_var_map :: type_info_var_map,
cm_typeclass_info_map :: typeclass_info_map,
cm_int_const_map :: int_const_map,
cm_const_struct_var_map :: const_struct_var_map
).
:- pred get_cache_maps_snapshot(string::in, cache_maps::out,
poly_info::in, poly_info::out) is det.
:- pred set_cache_maps_snapshot(string::in, cache_maps::in,
poly_info::in, poly_info::out) is det.
:- pred empty_cache_maps(poly_info::in, poly_info::out) is det.
%---------------------------------------------------------------------------%
:- type var_maps
---> var_maps(
vm_snapshot_num :: int,
vm_var_table :: var_table,
vm_rtti_varmaps :: rtti_varmaps,
vm_cache_maps :: cache_maps
).
:- pred get_var_maps_snapshot(string::in, var_maps::out,
poly_info::in, poly_info::out) is det.
:- pred set_var_maps_snapshot(string::in, var_maps::in,
poly_info::in, poly_info::out) is det.
%---------------------------------------------------------------------------%
:- pred get_poly_const(int::in, prog_var::out, list(hlds_goal)::out,
poly_info::in, poly_info::out) is det.
:- pred all_are_const_struct_args(
assoc_list(prog_var, maybe(const_struct_arg))::in,
list(const_struct_arg)::out) is semidet.
:- pred get_inst_of_const_struct_arg(const_struct_db::in, const_struct_arg::in,
mer_inst::out) is det.
%---------------------------------------------------------------------------%
:- type maybe_selected_pred
---> is_not_selected_pred
; is_selected_pred.
:- pred poly_info_get_selected_pred(maybe_selected_pred::out,
io::di, io::uo) is det.
:- pred poly_info_set_selected_pred(maybe_selected_pred::in,
io::di, io::uo) is det.
:- pred poly_info_get_indent_level(int::out, io::di, io::uo) is det.
:- pred poly_info_set_indent_level(int::in, io::di, io::uo) is det.
:- pred poly_info_get_debug_stream(poly_info::in, io.text_output_stream::out,
io::di, io::uo) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.make_goal.
:- import_module hlds.status.
:- import_module libs.
:- import_module libs.globals.
:- import_module bool.
:- import_module int.
:- import_module string.
:- import_module varset.
%---------------------------------------------------------------------------%
:- type poly_info
---> poly_info(
poly_module_info :: module_info,
poly_var_table :: var_table,
poly_rtti_varmaps :: rtti_varmaps,
poly_typevarset :: tvarset,
poly_tvar_kind_map :: tvar_kind_map,
% Specifies why each constraint that was eliminated from the
% pred was able to be eliminated (this allows us to efficiently
% construct the dictionary).
% Note that the rtti_varmaps is separate from the
% constraint_proof_map, since the second is the information
% calculated during typechecking, while the first is
% the information calculated in the polymorphism pass.
poly_proof_map :: constraint_proof_map,
% Specifies the constraints at each location in the goal.
poly_constraint_map :: constraint_map,
% The next four maps hold information about what
% type_ctor_infos, type_infos, base_typeclass_infos,
% typeclass_infos and ints are guaranteed to be available
% (i.e. created by previous code on all execution paths)
% at the current point in the code, so they can be reused.
% The fifth field counts the number of times that one of these
% variables has in fact been reused.
%
% The type_infos and typeclass_infos are in the first two maps.
% The type_ctor_infos and base_typeclass_infos are in the
% fourth map. The integers are in the third map.
% The fourth map also caches typeclass_infos for instance ids.
poly_type_info_var_map :: type_info_var_map,
poly_typeclass_info_map :: typeclass_info_map,
poly_int_const_map :: int_const_map,
poly_const_struct_var_map :: const_struct_var_map,
poly_num_reuses :: int,
poly_snapshot_num :: int,
% The database of constant structures of the module.
% If a type_info or typeclass_info we construct is a constant
% term, we allocate it in this database.
poly_const_struct_db :: const_struct_db,
poly_defined_where :: defined_where,
poly_must_requantify :: maybe_must_requantify,
% The list of errors we have discovered during the polymorphism
% pass.
poly_errors :: list(error_spec)
).
%---------------------------------------------------------------------------%
init_poly_info(ModuleInfo, PredInfo, ClausesInfo, PolyInfo) :-
clauses_info_get_var_table(ClausesInfo, VarTable),
pred_info_get_typevarset(PredInfo, TypeVarSet),
pred_info_get_tvar_kind_map(PredInfo, TypeVarKinds),
pred_info_get_constraint_proof_map(PredInfo, ProofMap),
pred_info_get_constraint_map(PredInfo, ConstraintMap),
rtti_varmaps_init(RttiVarMaps),
map.init(TypeInfoVarMap),
map.init(TypeClassInfoMap),
map.init(IntConstMap),
map.init(ConstStructVarMap),
NumReuses = 0,
SnapshotNum = 0,
module_info_get_const_struct_db(ModuleInfo, ConstStructDb),
pred_info_get_status(PredInfo, PredStatus),
pred_status_defined_in_this_module(PredStatus) = InThisModule,
( InThisModule = yes, DefinedWhere = defined_in_this_module
; InThisModule = no, DefinedWhere = defined_in_other_module
),
Requant = no_must_requantify,
Specs = [],
PolyInfo = poly_info(ModuleInfo, VarTable, RttiVarMaps,
TypeVarSet, TypeVarKinds, ProofMap, ConstraintMap,
TypeInfoVarMap, TypeClassInfoMap, IntConstMap, ConstStructVarMap,
NumReuses, SnapshotNum, ConstStructDb, DefinedWhere, Requant, Specs).
create_poly_info(ModuleInfo, PredInfo, ProcInfo, PolyInfo) :-
pred_info_get_typevarset(PredInfo, TypeVarSet),
pred_info_get_tvar_kind_map(PredInfo, TypeVarKinds),
pred_info_get_constraint_proof_map(PredInfo, ProofMap),
pred_info_get_constraint_map(PredInfo, ConstraintMap),
proc_info_get_var_table(ProcInfo, VarTable),
proc_info_get_rtti_varmaps(ProcInfo, RttiVarMaps),
map.init(TypeInfoVarMap),
map.init(TypeClassInfoMap),
map.init(IntConstMap),
map.init(ConstStructVarMap),
NumReuses = 0,
SnapshotNum = 0,
module_info_get_const_struct_db(ModuleInfo, ConstStructDb),
pred_info_get_status(PredInfo, PredStatus),
pred_status_defined_in_this_module(PredStatus) = InThisModule,
( InThisModule = yes, DefinedWhere = defined_in_this_module
; InThisModule = no, DefinedWhere = defined_in_other_module
),
Requant = no_must_requantify,
Specs = [],
PolyInfo = poly_info(ModuleInfo, VarTable, RttiVarMaps,
TypeVarSet, TypeVarKinds, ProofMap, ConstraintMap,
TypeInfoVarMap, TypeClassInfoMap, IntConstMap, ConstStructVarMap,
NumReuses, SnapshotNum, ConstStructDb, DefinedWhere, Requant, Specs).
poly_info_extract(Info, Specs, !PredInfo, !ProcInfo, !:ModuleInfo) :-
Info = poly_info(!:ModuleInfo, VarTable, RttiVarMaps,
TypeVarSet, TypeVarKinds, _ProofMap, _ConstraintMap,
_TypeInfoVarMap, _TypeClassInfoMap, _IntConstMap, _ConstStructVarMap,
_NumReuses, _SnapshotNum, ConstStructDb, _DefinedWhere,
_Requant, Specs),
module_info_set_const_struct_db(ConstStructDb, !ModuleInfo),
% Set the new values of the fields in proc_info and pred_info.
proc_info_set_var_table(VarTable, !ProcInfo),
proc_info_set_rtti_varmaps(RttiVarMaps, !ProcInfo),
pred_info_set_typevarset(TypeVarSet, !PredInfo),
pred_info_set_tvar_kind_map(TypeVarKinds, !PredInfo).
%---------------------------------------------------------------------------%
:- pragma inline(pred(poly_info_get_module_info/2)).
:- pragma inline(pred(poly_info_get_var_table/2)).
:- pragma inline(pred(poly_info_get_rtti_varmaps/2)).
:- pragma inline(pred(poly_info_get_typevarset/2)).
:- pragma inline(pred(poly_info_get_tvar_kind_map/2)).
:- pragma inline(pred(poly_info_get_proof_map/2)).
:- pragma inline(pred(poly_info_get_constraint_map/2)).
:- pragma inline(pred(poly_info_get_type_info_var_map/2)).
:- pragma inline(pred(poly_info_get_typeclass_info_map/2)).
:- pragma inline(pred(poly_info_get_const_struct_var_map/2)).
:- pragma inline(pred(poly_info_get_int_const_map/2)).
:- pragma inline(pred(poly_info_get_num_reuses/2)).
:- pragma inline(pred(poly_info_get_const_struct_db/2)).
:- pragma inline(pred(poly_info_get_errors/2)).
poly_info_get_module_info(PI, X) :-
X = PI ^ poly_module_info.
poly_info_get_var_table(PI, X) :-
X = PI ^ poly_var_table.
poly_info_get_rtti_varmaps(PI, X) :-
X = PI ^ poly_rtti_varmaps.
poly_info_get_typevarset(PI, X) :-
X = PI ^ poly_typevarset.
poly_info_get_tvar_kind_map(PI, X) :-
X = PI ^ poly_tvar_kind_map.
poly_info_get_proof_map(PI, X) :-
X = PI ^ poly_proof_map.
poly_info_get_constraint_map(PI, X) :-
X = PI ^ poly_constraint_map.
poly_info_get_type_info_var_map(PI, X) :-
X = PI ^ poly_type_info_var_map.
poly_info_get_typeclass_info_map(PI, X) :-
X = PI ^ poly_typeclass_info_map.
poly_info_get_int_const_map(PI, X) :-
X = PI ^ poly_int_const_map.
poly_info_get_const_struct_var_map(PI, X) :-
X = PI ^ poly_const_struct_var_map.
poly_info_get_num_reuses(PI, X) :-
X = PI ^ poly_num_reuses.
poly_info_get_const_struct_db(PI, X) :-
X = PI ^ poly_const_struct_db.
poly_info_get_defined_where(PI, X) :-
X = PI ^ poly_defined_where.
poly_info_get_must_requantify(PI, X) :-
X = PI ^ poly_must_requantify.
poly_info_get_errors(PI, X) :-
X = PI ^ poly_errors.
:- pragma inline(pred(poly_info_set_var_table/3)).
:- pragma inline(pred(poly_info_set_var_table_rtti/4)).
:- pragma inline(pred(poly_info_set_rtti_varmaps/3)).
:- pragma inline(pred(poly_info_set_typevarset/3)).
:- pragma inline(pred(poly_info_set_proof_map/3)).
:- pragma inline(pred(poly_info_set_type_info_var_map/3)).
:- pragma inline(pred(poly_info_set_typeclass_info_map/3)).
:- pragma inline(pred(poly_info_set_int_const_map/3)).
:- pragma inline(pred(poly_info_set_const_struct_var_map/3)).
:- pragma inline(pred(poly_info_set_num_reuses/3)).
:- pragma inline(pred(poly_info_set_const_struct_db/3)).
:- pragma inline(pred(poly_info_set_errors/3)).
poly_info_set_var_table(X, !PI) :-
!PI ^ poly_var_table := X.
poly_info_set_var_table_rtti(X, Y, !PI) :-
!:PI = ((!.PI
^ poly_var_table := X)
^ poly_rtti_varmaps := Y).
poly_info_set_rtti_varmaps(X, !PI) :-
( if private_builtin.pointer_equal(X, !.PI ^ poly_rtti_varmaps) then
true
else
!PI ^ poly_rtti_varmaps := X
).
poly_info_set_typevarset(X, !PI) :-
!PI ^ poly_typevarset := X.
poly_info_set_proof_map(X, !PI) :-
( if private_builtin.pointer_equal(X, !.PI ^ poly_proof_map) then
true
else
!PI ^ poly_proof_map := X
).
poly_info_set_type_info_var_map(X, !PI) :-
( if private_builtin.pointer_equal(X, !.PI ^ poly_type_info_var_map) then
true
else
!PI ^ poly_type_info_var_map := X
).
poly_info_set_typeclass_info_map(X, !PI) :-
( if private_builtin.pointer_equal(X, !.PI ^ poly_typeclass_info_map) then
true
else
!PI ^ poly_typeclass_info_map := X
).
poly_info_set_int_const_map(X, !PI) :-
( if private_builtin.pointer_equal(X, !.PI ^ poly_int_const_map) then
true
else
!PI ^ poly_int_const_map := X
).
poly_info_set_const_struct_var_map(X, !PI) :-
( if
private_builtin.pointer_equal(X, !.PI ^ poly_const_struct_var_map)
then
true
else
!PI ^ poly_const_struct_var_map := X
).
poly_info_set_num_reuses(X, !PI) :-
( if X = !.PI ^ poly_num_reuses then
true
else
!PI ^ poly_num_reuses := X
).
poly_info_set_const_struct_db(X, !PI) :-
( if private_builtin.pointer_equal(X, !.PI ^ poly_const_struct_db) then
true
else
!PI ^ poly_const_struct_db := X
).
poly_info_set_must_requantify(!PI) :-
!PI ^ poly_must_requantify := must_requantify.
poly_info_set_errors(X, !PI) :-
!PI ^ poly_errors := X.
% i read same diff same%
% 0 6245285 0 1560789 0.000% varset
% 1 6662703 0 0 vartypes
% 2 0 1110 129008 0.853% varset, vartypes
% 17 0 131468 1961967 6.280% varset, vartypes, rtti_varmaps
% 3 3052707 4 245972 0.002% typevarset
% 4 1578929 0 0 tvar_kind_map
% 5 8959328 2116731 988195 68.173% rtti_varmaps
% 6 14812 3980 4058 49.515% proof_map
% 7 3030093 0 0 constraint_map
% 8 811687 776589 288951 72.882% type_info_var_map
% 9 385071 863384 6104 99.298% typeclass_info_map
% 10 385706 863310 8464 99.029% int_const_map
% 11 253310 331092 41528 88.855% num_reuses
% 12 2559364 25821 15631 62.291% const_struct_db
% 13 583633 780835 286464 73.160% const_struct_var_map
% 14 0 0 0 pred_info
% 15 3933469 0 0 module_info
% 16 0 431065 87104 83.190% cache_maps_snapshot
% :- pragma foreign_decl("C", local,
% "
% #define MR_NUM_INFO_STATS 18
% unsigned long MR_stats_read[MR_NUM_INFO_STATS];
% unsigned long MR_stats_same[MR_NUM_INFO_STATS];
% unsigned long MR_stats_diff[MR_NUM_INFO_STATS];
% ").
%
% :- pred gather_poly_info_read_stats(int::in,
% poly_info::in, poly_info::out) is det.
%
% :- pragma foreign_proc("C",
% gather_poly_info_read_stats(N::in, PI0::in, PI::out),
% [will_not_call_mercury, promise_pure],
% "
% ++MR_stats_read[N];
% PI = PI0;
% ").
%
% :- pred gather_poly_info_write_stats(int::in, T::in, T::in,
% poly_info::in, poly_info::out) is det.
%
% :- pragma foreign_proc("C",
% gather_poly_info_write_stats(N::in, Old::in, New::in,
% PI0::in, PI::out),
% [will_not_call_mercury, promise_pure],
% "
% if (((MR_Unsigned) Old) == ((MR_Unsigned) New)) {
% ++MR_stats_same[N];
% } else {
% ++MR_stats_diff[N];
% }
%
% PI = PI0;
% ").
%
% :- pred gather_poly_info_write_stats_2(int::in, T::in, T::in, U::in, U::in,
% poly_info::in, poly_info::out) is det.
%
% :- pragma foreign_proc("C",
% gather_poly_info_write_stats_2(N::in, OldA::in, NewA::in,
% OldB::in, NewB::in, PI0::in, PI::out),
% [will_not_call_mercury, promise_pure],
% "
% if ((((MR_Unsigned) OldA) == ((MR_Unsigned) NewA)) &&
% (((MR_Unsigned) OldB) == ((MR_Unsigned) NewB)))
% {
% ++MR_stats_same[N];
% } else {
% ++MR_stats_diff[N];
% }
%
% PI = PI0;
% ").
%
% :- pred gather_poly_info_write_stats_3(int::in, T::in, T::in, U::in, U::in,
% V::in, V::in, poly_info::in, poly_info::out) is det.
%
% :- pragma foreign_proc("C",
% gather_poly_info_write_stats_3(N::in, OldA::in, NewA::in,
% OldB::in, NewB::in, OldC::in, NewC::in, PI0::in, PI::out),
% [will_not_call_mercury, promise_pure],
% "
% if ((((MR_Unsigned) OldA) == ((MR_Unsigned) NewA)) &&
% (((MR_Unsigned) OldB) == ((MR_Unsigned) NewB)) &&
% (((MR_Unsigned) OldC) == ((MR_Unsigned) NewC)))
% {
% ++MR_stats_same[N];
% } else {
% ++MR_stats_diff[N];
% }
%
% PI = PI0;
% ").
%
% :- interface.
% :- import_module io.
% :- pred write_poly_info_stats(io::di, io::uo) is det.
% :- implementation.
%
% :- pragma foreign_proc("C",
% write_poly_info_stats(IO0::di, IO::uo),
% [will_not_call_mercury, promise_pure],
% "
% FILE *fp;
%
% fp = fopen(""/tmp/POLY_INFO_STATS"", ""a"");
% if (fp != NULL) {
% int i;
% for (i = 0; i < MR_NUM_INFO_STATS; i++) {
% fprintf(fp, ""stat_rsd %d %lu %lu %lu\\n"",
% i, MR_stats_read[i], MR_stats_same[i], MR_stats_diff[i]);
% }
% }
%
% IO = IO0;
% ").
%---------------------------------------------------------------------------%
get_cache_maps_snapshot(Name, CacheMaps, !Info) :-
poly_info_get_type_info_var_map(!.Info, TypeInfoVarMap),
poly_info_get_typeclass_info_map(!.Info, TypeClassInfoMap),
poly_info_get_int_const_map(!.Info, IntConstMap),
poly_info_get_const_struct_var_map(!.Info, ConstStructVarMap),
SnapshotNum = !.Info ^ poly_snapshot_num,
CacheMaps = cache_maps(SnapshotNum, TypeInfoVarMap, TypeClassInfoMap,
IntConstMap, ConstStructVarMap),
!Info ^ poly_snapshot_num := SnapshotNum + 1,
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
get_selected_pred(SelectedPred, !IO),
get_indent_level(Level, !IO),
( if
SelectedPred = is_selected_pred,
Name \= ""
then
poly_info_get_debug_stream(!.Info, Stream, !IO),
IndentStr = string.duplicate_char(' ', Level * 4),
poly_info_get_var_table(!.Info, VarTable),
var_table_count(VarTable, NumVars),
io.format(Stream, "%sget_cache_maps_snapshot %d %s\n",
[s(IndentStr), i(SnapshotNum), s(Name)], !IO),
io.format(Stream, "%snum_allocated vars: %d\n\n",
[s(IndentStr), i(NumVars)], !IO)
else
true
)
).
set_cache_maps_snapshot(Name, CacheMaps, !Info) :-
CacheMaps = cache_maps(SnapshotNum, TypeInfoVarMap, TypeClassInfoMap,
IntConstMap, ConstStructVarMap),
( if
private_builtin.pointer_equal(TypeInfoVarMap,
!.Info ^ poly_type_info_var_map),
private_builtin.pointer_equal(TypeClassInfoMap,
!.Info ^ poly_typeclass_info_map),
private_builtin.pointer_equal(IntConstMap,
!.Info ^ poly_int_const_map),
private_builtin.pointer_equal(ConstStructVarMap,
!.Info ^ poly_const_struct_var_map)
then
true
else
!:Info = ((((!.Info
^ poly_type_info_var_map := TypeInfoVarMap)
^ poly_typeclass_info_map := TypeClassInfoMap)
^ poly_int_const_map := IntConstMap)
^ poly_const_struct_var_map := ConstStructVarMap)
),
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
get_selected_pred(SelectedPred, !IO),
get_indent_level(Level, !IO),
( if
SelectedPred = is_selected_pred,
Name \= ""
then
poly_info_get_debug_stream(!.Info, Stream, !IO),
IndentStr = string.duplicate_char(' ', Level * 4),
poly_info_get_var_table(!.Info, VarTable),
var_table_count(VarTable, NumVars),
io.format(Stream, "%sset_cache_maps_snapshot %d %s\n",
[s(IndentStr), i(SnapshotNum), s(Name)], !IO),
io.format(Stream, "%snum_allocated vars: %d\n\n",
[s(IndentStr), i(NumVars)], !IO),
io.format(Stream, "%stype_info_var_map ", [s(IndentStr)], !IO),
io.write_line(Stream, CacheMaps ^ cm_type_info_var_map, !IO),
io.format(Stream, "%stypeclass_info_map ",
[s(IndentStr)], !IO),
io.write_line(Stream, CacheMaps ^ cm_typeclass_info_map, !IO),
io.format(Stream, "%sstruct_var_map ", [s(IndentStr)], !IO),
io.write_line(Stream,
CacheMaps ^ cm_const_struct_var_map, !IO),
io.nl(Stream, !IO)
else
true
)
).
empty_cache_maps(!Info) :-
poly_info_set_type_info_var_map(map.init, !Info),
poly_info_set_typeclass_info_map(map.init, !Info),
poly_info_set_int_const_map(map.init, !Info),
poly_info_set_const_struct_var_map(map.init, !Info).
%---------------------------------------------------------------------------%
get_var_maps_snapshot(Name, VarMaps, !Info) :-
SnapshotNum = !.Info ^ poly_snapshot_num,
poly_info_get_var_table(!.Info, VarTable),
poly_info_get_rtti_varmaps(!.Info, RttiVarMaps),
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
get_selected_pred(SelectedPred, !IO),
get_indent_level(Level, !IO),
(
SelectedPred = is_not_selected_pred
;
SelectedPred = is_selected_pred,
poly_info_get_debug_stream(!.Info, Stream, !IO),
IndentStr = string.duplicate_char(' ', Level * 4),
var_table_count(VarTable, NumVars),
io.format(Stream, "%sget_var_maps_snapshot %d %s\n",
[s(IndentStr), i(SnapshotNum), s(Name)], !IO),
io.format(Stream, "%snum_allocated vars: %d\n\n",
[s(IndentStr), i(NumVars)], !IO)
)
),
get_cache_maps_snapshot("", CacheMaps, !Info),
VarMaps = var_maps(SnapshotNum, VarTable, RttiVarMaps, CacheMaps).
set_var_maps_snapshot(Name, VarMaps, !Info) :-
VarMaps = var_maps(SnapshotNum, VarTable, RttiVarMaps, CacheMaps),
trace [compiletime(flag("debug_poly_caches")), io(!IO)] (
get_selected_pred(SelectedPred, !IO),
get_indent_level(Level, !IO),
(
SelectedPred = is_not_selected_pred
;
SelectedPred = is_selected_pred,
poly_info_get_debug_stream(!.Info, Stream, !IO),
IndentStr = string.duplicate_char(' ', Level * 4),
io.format(Stream, "%sset_var_maps_snapshot %d %s\n",
[s(IndentStr), i(SnapshotNum), s(Name)], !IO),
io.format(Stream, "%stype_info_var_map ",
[s(IndentStr)], !IO),
io.write_line(Stream, CacheMaps ^ cm_type_info_var_map, !IO),
io.format(Stream, "%stypeclass_info_map ",
[s(IndentStr)], !IO),
io.write_line(Stream, CacheMaps ^ cm_typeclass_info_map, !IO),
io.format(Stream, "%sstruct_var_map ", [s(IndentStr)], !IO),
io.write_line(Stream,
CacheMaps ^ cm_const_struct_var_map, !IO),
io.nl(Stream, !IO)
)
),
poly_info_set_var_table_rtti(VarTable, RttiVarMaps, !Info),
set_cache_maps_snapshot("", CacheMaps, !Info).
%---------------------------------------------------------------------------%
get_poly_const(IntConst, IntVar, Goals, !Info) :-
poly_info_get_int_const_map(!.Info, IntConstMap0),
( if map.search(IntConstMap0, IntConst, IntVarPrime) then
poly_info_get_num_reuses(!.Info, NumReuses),
poly_info_set_num_reuses(NumReuses + 1, !Info),
IntVar = IntVarPrime,
Goals = []
else
Name = "PolyConst" ++ string.int_to_string(IntConst),
poly_info_get_var_table(!.Info, VarTable0),
make_int_const_construction_alloc(IntConst, Name, Goal, IntVar,
VarTable0, VarTable),
poly_info_set_var_table(VarTable, !Info),
map.det_insert(IntConst, IntVar, IntConstMap0, IntConstMap),
poly_info_set_int_const_map(IntConstMap, !Info),
Goals = [Goal]
).
all_are_const_struct_args([], []).
all_are_const_struct_args([VarMCA | VarsMCAs], [ConstArg | ConstArgs]) :-
VarMCA = _Var - MCA,
MCA = yes(ConstArg),
all_are_const_struct_args(VarsMCAs, ConstArgs).
get_inst_of_const_struct_arg(ConstStructDb, ConstArg, Inst) :-
(
ConstArg = csa_constant(ConsId, _),
Inst = bound(shared, inst_test_results_fgtc,
[bound_functor(ConsId, [])])
;
ConstArg = csa_const_struct(StructNum),
lookup_const_struct_num(ConstStructDb, StructNum, Struct),
Struct = const_struct(_, _, _, Inst, _)
).
%---------------------------------------------------------------------------%
:- mutable(selected_pred, maybe_selected_pred, is_not_selected_pred, ground,
[untrailed, attach_to_io_state]).
:- mutable(indent_level, int, 0, ground,
[untrailed, attach_to_io_state]).
poly_info_get_selected_pred(Selected, !IO) :-
get_selected_pred(Selected, !IO).
poly_info_set_selected_pred(Selected, !IO) :-
set_selected_pred(Selected, !IO).
poly_info_get_indent_level(Level, !IO) :-
get_indent_level(Level, !IO).
poly_info_set_indent_level(Level, !IO) :-
set_indent_level(Level, !IO).
poly_info_get_debug_stream(PolyInfo, Stream, !IO) :-
poly_info_get_module_info(PolyInfo, ModuleInfo),
module_info_get_globals(ModuleInfo, Globals),
module_info_get_name(ModuleInfo, ModuleName),
get_debug_output_stream(Globals, ModuleName, Stream, !IO).
%---------------------------------------------------------------------------%
:- end_module check_hlds.polymorphism_info.
%---------------------------------------------------------------------------%