Files
mercury/compiler/post_term_analysis.m
Julien Fischer 459847a064 Move the univ, maybe, pair and unit types from std_util into their own
Estimated hours taken: 18
Branches: main

Move the univ, maybe, pair and unit types from std_util into their own
modules.  std_util still contains the general purpose higher-order programming
constructs.

library/std_util.m:
	Move univ, maybe, pair and unit (plus any other related types
	and procedures) into their own modules.

library/maybe.m:
	New module.  This contains the maybe and maybe_error types and
	the associated procedures.

library/pair.m:
	New module.  This contains the pair type and associated procedures.

library/unit.m:
	New module. This contains the types unit/0 and unit/1.

library/univ.m:
	New module. This contains the univ type and associated procedures.

library/library.m:
	Add the new modules.

library/private_builtin.m:
	Update the declaration of the type_ctor_info struct for univ.

runtime/mercury.h:
	Update the declaration for the type_ctor_info struct for univ.

runtime/mercury_mcpp.h:
runtime/mercury_hlc_types.h:
	Update the definition of MR_Univ.

runtime/mercury_init.h:
	Fix a comment: ML_type_name is now exported from type_desc.m.

compiler/mlds_to_il.m:
	Update the the name of the module that defines univs (which are
	handled specially by the il code generator.)

library/*.m:
compiler/*.m:
browser/*.m:
mdbcomp/*.m:
profiler/*.m:
deep_profiler/*.m:
	Conform to the above changes.  Import the new modules where they
	are needed; don't import std_util where it isn't needed.

	Fix formatting in lots of modules.  Delete duplicate module
	imports.

tests/*:
	Update the test suite to confrom to the above changes.
2006-03-29 08:09:58 +00:00

256 lines
9.3 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%----------------------------------------------------------------------------%
% Copyright (C) 2005-2006 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: post_term_analysis.m
% Main author: juliensf
%
% This module contains various checks that rely on the information produced by
% termination analysis.
%
% Currently, the only thing implemented in this module is a check to see if
% user-defined special predicates terminate. A warning is emitted for all
% those that do not.
%
%----------------------------------------------------------------------------%
:- module transform_hlds.post_term_analysis.
:- interface.
:- import_module hlds.hlds_module.
:- import_module io.
:- pred run_post_term_analysis(module_info::in, io::di, io::uo) is det.
%----------------------------------------------------------------------------%
%----------------------------------------------------------------------------%
:- implementation.
:- import_module backend_libs.
:- import_module backend_libs.foreign.
:- import_module hlds.goal_form.
:- import_module hlds.goal_util.
:- import_module hlds.hlds_data.
:- import_module hlds.hlds_error_util.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_out.
:- import_module hlds.hlds_pred.
:- import_module hlds.special_pred.
:- import_module libs.compiler_util.
:- import_module libs.globals.
:- import_module libs.options.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.error_util.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_type.
:- import_module bool.
:- import_module list.
:- import_module map.
:- import_module maybe.
:- import_module pair.
:- import_module string.
%----------------------------------------------------------------------------%
run_post_term_analysis(ModuleInfo, !IO) :-
warn_non_term_user_special_preds(ModuleInfo, !IO).
%----------------------------------------------------------------------------%
%
% Warn about user-defined special predicates that do not terminate
%
% We check the termination status of user-defined special predicates by taking
% the body goal of the compiler generated wrapper predicate and checking if
% that terminates. We cannot check the termination status of the compiler
% generated wrappers directly, because termination analysis always assumes
% that they terminate.
%
% Since all of the special predicates of interest here have to be defined in
% the same module as the type that uses them, we only check locally defined
% types. The ones for imported types will be checked when the relevant module
% is compiled and analysed.
:- pred warn_non_term_user_special_preds(module_info::in, io::di, io::uo)
is det.
warn_non_term_user_special_preds(ModuleInfo, !IO) :-
globals.io_lookup_bool_option(termination, Termination, !IO),
globals.io_lookup_bool_option(warn_non_term_special_preds,
WarnSpecialPreds, !IO),
globals.io_lookup_bool_option(make_optimization_interface, MakeOptInt,
!IO),
globals.io_lookup_bool_option(transitive_optimization, TransIntermodOpt,
!IO),
(
Termination = yes, WarnSpecialPreds = yes,
%
% Don't run this pass if we are only building the optimization
% interface and we are compiling with
% `--transitive-intermodule-optimization' enabled because we'll get
% more accurate results when we build the .trans_opt files. Any
% warnings this time around may be spurious.
%
not (MakeOptInt = yes, TransIntermodOpt = yes)
->
module_info_get_special_pred_map(ModuleInfo, SpecialPredMap),
module_info_get_type_table(ModuleInfo, TypeTable),
map.foldl(warn_non_term_user_special_pred(ModuleInfo, TypeTable),
SpecialPredMap, !IO)
;
true
).
:- pred warn_non_term_user_special_pred(module_info::in, type_table::in,
special_pred::in, pred_id::in, io::di, io::uo) is det.
warn_non_term_user_special_pred(ModuleInfo, TypeTable,
SpecialPredId - TypeCtor, PredId, !IO) :-
%
% index predicates cannot be defined by the user and should
% always terminate by design. Do not perform this
% check for builtin types that don't have hlds_type_defns.
%
BuiltinTypeCtors = builtin_type_ctors_with_no_hlds_type_defn,
(
SpecialPredId \= spec_pred_index,
not list.member(TypeCtor, BuiltinTypeCtors)
->
map.lookup(TypeTable, TypeCtor, TypeDefn),
get_type_defn_status(TypeDefn, ImportStatus),
(
status_defined_in_this_module(ImportStatus, yes)
->
process_special_pred_for_type(ModuleInfo,
SpecialPredId, TypeCtor, PredId, TypeDefn, !IO)
;
true
)
;
true
).
% If the specified special predicate for the given type is user-defined
% then check that it terminates. Emit a warning if it does not.
%
:- pred process_special_pred_for_type(module_info::in,
special_pred_id::in, type_ctor::in, pred_id::in,
hlds_type_defn::in, io::di, io::uo) is det.
process_special_pred_for_type(ModuleInfo, SpecialPredId, TypeCtor,
PredId, TypeDefn, !IO) :-
(
special_pred_needs_term_check(ModuleInfo, SpecialPredId, TypeDefn)
->
% Compiler generated special preds are always mode 0.
proc_id_to_int(ProcId, 0),
module_info_pred_proc_info(ModuleInfo, PredId, ProcId, _, ProcInfo),
proc_info_get_goal(ProcInfo, BodyGoal),
%
% We cannot just look up the the termination_info because the
% termination status of compiler generated wrapper predicates for
% special preds is always set to terminates. Instead, we check if the
% body of the generated wrapper predicate terminates.
%
( not goal_cannot_loop(ModuleInfo, BodyGoal) ->
get_type_defn_context(TypeDefn, Context),
emit_non_term_user_special_warning(Context, SpecialPredId,
TypeCtor, !IO)
;
true
)
;
true
).
% Succeeds if the specified type of special_pred for this type needs to
% have its termination status checked.
%
:- pred special_pred_needs_term_check(module_info::in,
special_pred_id::in, hlds_type_defn::in) is semidet.
special_pred_needs_term_check(ModuleInfo, SpecialPredId, TypeDefn) :-
get_type_defn_body(TypeDefn, TypeBody),
(
% Always check solver type initialisation
% predicates since they are always user-defined.
SpecialPredId = spec_pred_init
;
get_user_unify_compare(ModuleInfo, TypeBody, UnifyCompare),
(
UnifyCompare = unify_compare(MaybeUnify, MaybeCompare),
(
MaybeUnify = yes(_),
SpecialPredId = spec_pred_unify
;
MaybeCompare = yes(_),
SpecialPredId = spec_pred_compare
)
;
UnifyCompare = abstract_noncanonical_type(_),
unexpected(this_file, "special_pred_needs_term" ++
"_check/3: type is local and " ++
"abstract_noncanonical")
)
).
% Succeeds if the given type has user-defined equality and/or comparison
% and returns the relevant information about which predicates implement it.
%
:- pred get_user_unify_compare(module_info::in, hlds_type_body::in,
unify_compare::out) is semidet.
get_user_unify_compare(_ModuleInfo, TypeBody, UnifyCompare) :-
TypeBody = du_type(_, _, _, yes(UnifyCompare), _, _).
get_user_unify_compare(ModuleInfo, TypeBody, UnifyCompare) :-
TypeBody = foreign_type(ForeignTypeBody),
UnifyCompare = foreign_type_body_has_user_defined_eq_comp_pred(
ModuleInfo, ForeignTypeBody).
get_user_unify_compare(_ModuleInfo, TypeBody, UnifyCompare) :-
TypeBody = solver_type(_, yes(UnifyCompare)).
:- pred emit_non_term_user_special_warning(prog_context::in,
special_pred_id::in, type_ctor::in, io::di, io::uo) is det.
emit_non_term_user_special_warning(Context, SpecialPred, TypeCtor, !IO) :-
TypeCtorString = hlds_out.type_ctor_to_string(TypeCtor),
(
SpecialPred = spec_pred_unify,
SpecialPredStr = "equality"
;
SpecialPred = spec_pred_compare,
SpecialPredStr = "comparison"
;
SpecialPred = spec_pred_init,
SpecialPredStr = "initialisation"
;
SpecialPred = spec_pred_index,
unexpected(this_file, "emit_non_term_user_special_" ++
"warning/5 index predicate.")
),
Pieces = [
words("Warning: the user-defined "),
fixed(SpecialPredStr ++ " predicate"),
words("for the type "),
fixed(TypeCtorString),
words("cannot be proven to terminate.")
],
report_warning(Context, 0, Pieces, !IO).
%----------------------------------------------------------------------------%
:- func this_file = string.
this_file = "post_term_analysis.m".
%----------------------------------------------------------------------------%
:- end_module post_term_analysis.
%----------------------------------------------------------------------------%