mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 09:53:36 +00:00
534 lines
20 KiB
Mathematica
534 lines
20 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-2011 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: term_norm.m.
|
|
% Main author: crs.
|
|
%
|
|
% This modules defines predicates for computing functor norms.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module transform_hlds.term_norm.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_goal.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module libs.
|
|
:- import_module libs.globals.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
:- import_module list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% The functor_info type contains information about how the weight
|
|
% of a term is calculated.
|
|
%
|
|
:- type functor_info.
|
|
|
|
% This predicate sets the functor_info depending on the value of the
|
|
% termination_norm or termination2_norm option.
|
|
%
|
|
:- func set_functor_info(module_info, globals.termination_norm) = functor_info.
|
|
|
|
% This predicate computes the weight of a functor and the set of arguments
|
|
% of that functor whose sizes should be counted towards the size of the
|
|
% whole term.
|
|
%
|
|
% NOTE: the list of arguments and the list of modes must have the same
|
|
% length. They must also *not* contain any typeinfo related arguments as
|
|
% this may cause an exception to be thrown when using the
|
|
% `--num-data-elems' norm. (This is because the weight table does not
|
|
% keep track of typeinfo related variables - it used to, but intervening
|
|
% compiler passes tend to do things to the code in the mean time, so the
|
|
% whole lot becomes inconsistent - in the end it is just easier to ignore
|
|
% them).
|
|
%
|
|
:- pred functor_norm(module_info::in, functor_info::in, type_ctor::in,
|
|
cons_id::in, int::out, list(prog_var)::in, list(prog_var)::out,
|
|
list(unify_mode)::in, list(unify_mode)::out) is det.
|
|
|
|
% This function computes a lower bound on the weight of a functor.
|
|
% If the lower bound is zero then the weight of that functor is also zero.
|
|
% If the lower bound is non-zero then there may be no upper bound
|
|
% on the size of the functor. (And if there were, this function
|
|
% would not tell you about it anyhow).
|
|
%
|
|
:- func functor_lower_bound(module_info, functor_info, type_ctor, cons_id)
|
|
= int.
|
|
|
|
% Succeeds if all values of the given type are zero size (for all norms).
|
|
%
|
|
:- pred zero_size_type(module_info::in, mer_type::in) is semidet.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.
|
|
:- import_module check_hlds.type_util.
|
|
:- import_module hlds.const_struct.
|
|
:- import_module hlds.hlds_data.
|
|
:- import_module parse_tree.prog_type.
|
|
|
|
:- import_module bool.
|
|
:- import_module int.
|
|
:- import_module map.
|
|
:- import_module one_or_more.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% We use semilinear norms (denoted by ||) to compute the sizes of terms.
|
|
% These have the form
|
|
%
|
|
% |f(t1, ... tn)| = weight(f) + sum of |ti|
|
|
% where i is an element of a set I, and I is a subset of {1, ... n}
|
|
%
|
|
% We currently support four kinds of semilinear norms.
|
|
% XXX Actually we currently only use three of them. `use_map/1' is unused.
|
|
|
|
:- type functor_info
|
|
---> simple
|
|
% All non-constant functors have weight 1, while constants
|
|
% have weight 0. Use the size of all subterms (I = {1, ..., n}.
|
|
|
|
; total
|
|
% All functors have weight = arity of the functor.
|
|
% Use the size of all subterms (I = {1, ..., n}.
|
|
|
|
; use_map(weight_table)
|
|
% The weight of each functor is given by the table.
|
|
% Use the size of all subterms (I = {1, ..., n}.
|
|
|
|
; use_map_and_args(weight_table).
|
|
% The weight of each functor is given by the table, and so is
|
|
% the set of arguments of the functor whose size should be counted
|
|
% (I is given by the table entry of the functor).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Calculate the weight to be assigned to each function symbol for the
|
|
% use_map and use_map_and_args semilinear norms.
|
|
%
|
|
% Given a type definition such as
|
|
%
|
|
% :- type t(Tk)
|
|
% ---> f1(a11, ... a1n1) where n1 is the arity of f1
|
|
% ; ...
|
|
% ; fm(am1, ... amnm) where nm is the arity of fm
|
|
%
|
|
% we check, for each aij, whether its type is recursive (i.e. it is t with
|
|
% type variable arguments that are a permutation of Tk). The weight info
|
|
% we compute for each functor will have a boolean list that has a `yes'
|
|
% for each recursive argument and a `no' for each nonrecursive argument.
|
|
% The weight to be assigned to the functor is the number of nonrecursive
|
|
% arguments, except that we assign a weight of at least 1 to all functors
|
|
% which are not constants.
|
|
|
|
:- type weight_table == map(pair(type_ctor, cons_id), weight_info).
|
|
|
|
:- type weight_info
|
|
---> weight(int, list(bool)).
|
|
|
|
:- pred find_weights(module_info::in, weight_table::out) is det.
|
|
|
|
find_weights(ModuleInfo, Weights) :-
|
|
module_info_get_type_table(ModuleInfo, TypeTable),
|
|
get_all_type_ctor_defns(TypeTable, TypeCtorsDefns),
|
|
map.init(Weights0),
|
|
list.foldl(find_weights_for_type, TypeCtorsDefns, Weights0, Weights).
|
|
|
|
:- pred find_weights_for_type(pair(type_ctor, hlds_type_defn)::in,
|
|
weight_table::in, weight_table::out) is det.
|
|
|
|
find_weights_for_type(TypeCtor - TypeDefn, !Weights) :-
|
|
hlds_data.get_type_defn_body(TypeDefn, TypeBody),
|
|
(
|
|
TypeBody = hlds_du_type(type_body_du(Constructors, _, _, _, _)),
|
|
hlds_data.get_type_defn_tparams(TypeDefn, TypeParams),
|
|
list.foldl(find_weights_for_cons(TypeCtor, TypeParams),
|
|
one_or_more_to_list(Constructors), !Weights)
|
|
;
|
|
% This type does not introduce any functors.
|
|
TypeBody = hlds_eqv_type(_)
|
|
;
|
|
% This type may introduce some functors,
|
|
% but we will never see them in this analysis.
|
|
TypeBody = hlds_abstract_type(_)
|
|
;
|
|
% This type does not introduce any functors.
|
|
TypeBody = hlds_foreign_type(_)
|
|
;
|
|
% This type does not introduce any functors.
|
|
TypeBody = hlds_solver_type(_)
|
|
).
|
|
|
|
:- pred find_weights_for_cons(type_ctor::in, list(type_param)::in,
|
|
constructor::in, weight_table::in, weight_table::out) is det.
|
|
|
|
find_weights_for_cons(TypeCtor, Params, Ctor, !Weights) :-
|
|
% For existentially typed data items the compiler may insert some
|
|
% typeinfo related arguments into the functor. We ignore these arguments
|
|
% when calculating the weight of a functor and we do not include them
|
|
% in the list of counted arguments.
|
|
Ctor = ctor(_Ordinal, _MaybeExistConstraints, SymName, Args, Arity,
|
|
_Context),
|
|
( if Arity > 0 then
|
|
find_and_count_nonrec_args(Args, TypeCtor, Params,
|
|
NumNonRec, ArgInfos0),
|
|
( if NumNonRec = 0 then
|
|
Weight = 1,
|
|
list.duplicate(Arity, yes, ArgInfos)
|
|
else
|
|
Weight = NumNonRec,
|
|
ArgInfos = ArgInfos0
|
|
),
|
|
WeightInfo = weight(Weight, ArgInfos)
|
|
else
|
|
WeightInfo = weight(0, [])
|
|
),
|
|
ConsId = cons(SymName, Arity, TypeCtor),
|
|
map.det_insert(TypeCtor - ConsId, WeightInfo, !Weights).
|
|
|
|
:- pred find_weights_for_tuple(arity::in, weight_info::out) is det.
|
|
|
|
find_weights_for_tuple(Arity, weight(Weight, ArgInfos)) :-
|
|
% None of the tuple arguments are recursive.
|
|
Weight = Arity,
|
|
list.duplicate(Arity, yes, ArgInfos).
|
|
|
|
:- pred find_and_count_nonrec_args(list(constructor_arg)::in,
|
|
type_ctor::in, list(type_param)::in,
|
|
int::out, list(bool)::out) is det.
|
|
|
|
find_and_count_nonrec_args([], _, _, 0, []).
|
|
find_and_count_nonrec_args([Arg | Args], Id, Params, NonRecArgs, ArgInfo) :-
|
|
find_and_count_nonrec_args(Args, Id, Params, NonRecArgs0, ArgInfo0),
|
|
( if is_arg_recursive(Arg, Id, Params) then
|
|
NonRecArgs = NonRecArgs0,
|
|
ArgInfo = [yes | ArgInfo0]
|
|
else
|
|
NonRecArgs = NonRecArgs0 + 1,
|
|
ArgInfo = [no | ArgInfo0]
|
|
).
|
|
|
|
:- pred is_arg_recursive(constructor_arg::in, type_ctor::in,
|
|
list(type_param)::in) is semidet.
|
|
|
|
is_arg_recursive(Arg, TypeCtor, Params) :-
|
|
ArgType = Arg ^ arg_type,
|
|
type_to_ctor_and_args(ArgType, ArgTypeCtor, ArgTypeArgs),
|
|
TypeCtor = ArgTypeCtor,
|
|
prog_type.type_list_to_var_list(ArgTypeArgs, ArgTypeParams),
|
|
list.perm(Params, ArgTypeParams).
|
|
|
|
:- pred search_weight_table(weight_table::in, type_ctor::in, cons_id::in,
|
|
weight_info::out) is semidet.
|
|
|
|
search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo) :-
|
|
( if map.search(WeightMap, TypeCtor - ConsId, WeightInfo0) then
|
|
WeightInfo = WeightInfo0
|
|
else if type_ctor_is_tuple(TypeCtor) then
|
|
TypeCtor = type_ctor(_, Arity),
|
|
find_weights_for_tuple(Arity, WeightInfo)
|
|
else
|
|
fail
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
set_functor_info(_ModuleInfo, norm_total) = total.
|
|
set_functor_info(_ModuleInfo, norm_simple) = simple.
|
|
set_functor_info(ModuleInfo, norm_num_data_elems) = FunctorInfo :-
|
|
find_weights(ModuleInfo, WeightMap),
|
|
FunctorInfo = use_map_and_args(WeightMap).
|
|
set_functor_info(ModuleInfo, norm_size_data_elems) = FunctorInfo :-
|
|
find_weights(ModuleInfo, WeightMap),
|
|
FunctorInfo = use_map(WeightMap).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
functor_norm(ModuleInfo, FunctorInfo, TypeCtor, ConsId, Gamma,
|
|
!Args, !Modes) :-
|
|
(
|
|
FunctorInfo = simple,
|
|
( if
|
|
ConsId = cons(_, Arity, _),
|
|
Arity \= 0
|
|
then
|
|
Gamma = 1
|
|
else if
|
|
ConsId = ground_term_const(ConstNum, _)
|
|
then
|
|
module_info_get_const_struct_db(ModuleInfo, ConstStructDb),
|
|
const_struct_count_cells(ConstStructDb, ConstNum, 0, Gamma)
|
|
else
|
|
Gamma = 0
|
|
)
|
|
;
|
|
FunctorInfo = total,
|
|
( if ConsId = cons(_, Arity, _) then
|
|
Gamma = Arity
|
|
else if ConsId = ground_term_const(ConstNum, _) then
|
|
module_info_get_const_struct_db(ModuleInfo, ConstStructDb),
|
|
const_struct_count_cell_arities(ConstStructDb, ConstNum, 0, Gamma)
|
|
else
|
|
Gamma = 0
|
|
)
|
|
;
|
|
FunctorInfo = use_map(WeightMap),
|
|
( if search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo) then
|
|
WeightInfo = weight(Gamma, _)
|
|
else if ConsId = ground_term_const(ConstNum, _) then
|
|
module_info_get_const_struct_db(ModuleInfo, ConstStructDb),
|
|
const_struct_count_cell_weights(ConstStructDb, WeightMap,
|
|
ConstNum, 0, Gamma)
|
|
else
|
|
Gamma = 0
|
|
)
|
|
;
|
|
FunctorInfo = use_map_and_args(WeightMap),
|
|
( if search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo) then
|
|
WeightInfo = weight(Gamma, UseArgList),
|
|
( if functor_norm_filter_args(UseArgList, !Args, !Modes) then
|
|
true
|
|
else
|
|
unexpected($pred, "unmatched lists")
|
|
)
|
|
else if ConsId = ground_term_const(ConstNum, _) then
|
|
% XXX Since ground_term_consts have no argument variables,
|
|
% we cannot filter those argument variables. I (zs) *think* that
|
|
% returning the !.Args and !.Modes (which should both be empty
|
|
% to begin with) does the right thing, but I am not sure.
|
|
module_info_get_const_struct_db(ModuleInfo, ConstStructDb),
|
|
const_struct_count_cell_filtered_weights(ConstStructDb, WeightMap,
|
|
ConstNum, 0, Gamma)
|
|
else
|
|
Gamma = 0
|
|
)
|
|
).
|
|
|
|
% This predicate will fail if the length of the input lists are not
|
|
% matched.
|
|
%
|
|
:- pred functor_norm_filter_args(list(bool)::in, list(prog_var)::in,
|
|
list(prog_var)::out, list(unify_mode)::in, list(unify_mode)::out)
|
|
is semidet.
|
|
|
|
functor_norm_filter_args([], [], [], [], []).
|
|
functor_norm_filter_args([yes | Bools], [Arg0 | Args0], [Arg0 | Args],
|
|
[Mode0 | Modes0], [Mode0 | Modes]) :-
|
|
functor_norm_filter_args(Bools, Args0, Args, Modes0, Modes).
|
|
functor_norm_filter_args([no | Bools], [_Arg0 | Args0], Args,
|
|
[_Mode0 | Modes0], Modes) :-
|
|
functor_norm_filter_args(Bools, Args0, Args, Modes0, Modes).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred const_struct_count_cells(const_struct_db::in, int::in,
|
|
int::in, int::out) is det.
|
|
|
|
const_struct_count_cells(ConstStructDb, ConstNum, !Gamma) :-
|
|
lookup_const_struct_num(ConstStructDb, ConstNum, ConstStruct),
|
|
ConstStruct = const_struct(_ConsId, Args, _, _, _),
|
|
!:Gamma = !.Gamma + 1,
|
|
const_struct_count_cells_args(ConstStructDb, Args, !Gamma).
|
|
|
|
:- pred const_struct_count_cells_args(const_struct_db::in,
|
|
list(const_struct_arg)::in, int::in, int::out) is det.
|
|
|
|
const_struct_count_cells_args(_ConstStructDb, [], !Gamma).
|
|
const_struct_count_cells_args(ConstStructDb, [Arg | Args], !Gamma) :-
|
|
(
|
|
Arg = csa_constant(_, _)
|
|
;
|
|
Arg = csa_const_struct(ArgConstNum),
|
|
const_struct_count_cells(ConstStructDb, ArgConstNum, !Gamma)
|
|
),
|
|
const_struct_count_cells_args(ConstStructDb, Args, !Gamma).
|
|
|
|
:- pred const_struct_count_cell_arities(const_struct_db::in, int::in,
|
|
int::in, int::out) is det.
|
|
|
|
const_struct_count_cell_arities(ConstStructDb, ConstNum, !Gamma) :-
|
|
lookup_const_struct_num(ConstStructDb, ConstNum, ConstStruct),
|
|
ConstStruct = const_struct(_ConsId, Args, _, _, _),
|
|
!:Gamma = !.Gamma + list.length(Args),
|
|
const_struct_count_cell_arities_args(ConstStructDb, Args, !Gamma).
|
|
|
|
:- pred const_struct_count_cell_arities_args(const_struct_db::in,
|
|
list(const_struct_arg)::in, int::in, int::out) is det.
|
|
|
|
const_struct_count_cell_arities_args(_ConstStructDb, [], !Gamma).
|
|
const_struct_count_cell_arities_args(ConstStructDb, [Arg | Args], !Gamma) :-
|
|
(
|
|
Arg = csa_constant(_, _)
|
|
;
|
|
Arg = csa_const_struct(ArgConstNum),
|
|
const_struct_count_cell_arities(ConstStructDb, ArgConstNum, !Gamma)
|
|
),
|
|
const_struct_count_cell_arities_args(ConstStructDb, Args, !Gamma).
|
|
|
|
:- pred const_struct_count_cell_weights(const_struct_db::in,
|
|
weight_table::in, int::in, int::in, int::out) is det.
|
|
|
|
const_struct_count_cell_weights(ConstStructDb, WeightMap, ConstNum, !Gamma) :-
|
|
lookup_const_struct_num(ConstStructDb, ConstNum, ConstStruct),
|
|
ConstStruct = const_struct(ConsId, Args, Type, _, _),
|
|
type_to_ctor_det(Type, TypeCtor),
|
|
( if search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo) then
|
|
WeightInfo = weight(ConsIdGamma, _),
|
|
!:Gamma = !.Gamma + ConsIdGamma,
|
|
const_struct_count_cell_weights_args(ConstStructDb, WeightMap,
|
|
Args, !Gamma)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred const_struct_count_cell_weights_args(const_struct_db::in,
|
|
weight_table::in, list(const_struct_arg)::in, int::in, int::out) is det.
|
|
|
|
const_struct_count_cell_weights_args(_ConstStructDb, _WeightMap, [], !Gamma).
|
|
const_struct_count_cell_weights_args(ConstStructDb, WeightMap,
|
|
[Arg | Args], !Gamma) :-
|
|
(
|
|
Arg = csa_constant(ConsId, Type),
|
|
type_to_ctor_det(Type, TypeCtor),
|
|
( if search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo) then
|
|
WeightInfo = weight(ConsIdGamma, _),
|
|
!:Gamma = !.Gamma + ConsIdGamma
|
|
else
|
|
true
|
|
)
|
|
;
|
|
Arg = csa_const_struct(ArgConstNum),
|
|
const_struct_count_cell_weights(ConstStructDb, WeightMap,
|
|
ArgConstNum, !Gamma)
|
|
),
|
|
const_struct_count_cell_weights_args(ConstStructDb, WeightMap,
|
|
Args, !Gamma).
|
|
|
|
:- pred const_struct_count_cell_filtered_weights(const_struct_db::in,
|
|
weight_table::in, int::in, int::in, int::out) is det.
|
|
|
|
const_struct_count_cell_filtered_weights(ConstStructDb, WeightMap,
|
|
ConstNum, !Gamma) :-
|
|
lookup_const_struct_num(ConstStructDb, ConstNum, ConstStruct),
|
|
ConstStruct = const_struct(ConsId, Args, Type, _, _),
|
|
type_to_ctor_det(Type, TypeCtor),
|
|
( if search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo) then
|
|
WeightInfo = weight(ConsIdGamma, UseArgs),
|
|
!:Gamma = !.Gamma + ConsIdGamma,
|
|
const_struct_count_cell_filtered_weights_args(ConstStructDb, WeightMap,
|
|
Args, UseArgs, !Gamma)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred const_struct_count_cell_filtered_weights_args(const_struct_db::in,
|
|
weight_table::in, list(const_struct_arg)::in, list(bool)::in,
|
|
int::in, int::out) is det.
|
|
|
|
const_struct_count_cell_filtered_weights_args(_ConstStructDb, _WeightMap,
|
|
[], [], !Gamma).
|
|
const_struct_count_cell_filtered_weights_args(_ConstStructDb, _WeightMap,
|
|
[], [_ | _], !Gamma) :-
|
|
unexpected($pred, "mismatched lists").
|
|
const_struct_count_cell_filtered_weights_args(_ConstStructDb, _WeightMap,
|
|
[_ | _], [], !Gamma) :-
|
|
unexpected($pred, "mismatched lists").
|
|
const_struct_count_cell_filtered_weights_args(ConstStructDb, WeightMap,
|
|
[Arg | Args], [UseArg | UseArgs], !Gamma) :-
|
|
(
|
|
UseArg = no
|
|
;
|
|
UseArg = yes,
|
|
(
|
|
Arg = csa_constant(ConsId, Type),
|
|
type_to_ctor_det(Type, TypeCtor),
|
|
( if
|
|
search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo)
|
|
then
|
|
WeightInfo = weight(ConsIdGamma, _),
|
|
!:Gamma = !.Gamma + ConsIdGamma
|
|
else
|
|
true
|
|
)
|
|
;
|
|
Arg = csa_const_struct(ArgConstNum),
|
|
const_struct_count_cell_filtered_weights(ConstStructDb, WeightMap,
|
|
ArgConstNum, !Gamma)
|
|
)
|
|
),
|
|
const_struct_count_cell_filtered_weights_args(ConstStructDb, WeightMap,
|
|
Args, UseArgs, !Gamma).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
functor_lower_bound(_ModuleInfo, FunctorInfo, TypeCtor, ConsId) = Weight :-
|
|
(
|
|
FunctorInfo = simple,
|
|
Weight = ( if ConsId = cons(_, Arity, _), Arity \= 0 then 1 else 0 )
|
|
;
|
|
FunctorInfo = total,
|
|
Weight = ( if ConsId = cons(_, Arity, _) then Arity else 0 )
|
|
;
|
|
FunctorInfo = use_map(WeightMap),
|
|
( if search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo) then
|
|
WeightInfo = weight(Weight, _)
|
|
else
|
|
Weight = 0
|
|
)
|
|
;
|
|
FunctorInfo = use_map_and_args(WeightMap),
|
|
( if search_weight_table(WeightMap, TypeCtor, ConsId, WeightInfo) then
|
|
WeightInfo = weight(Weight, _)
|
|
else
|
|
Weight = 0
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
zero_size_type(ModuleInfo, Type) :-
|
|
CtorCat = classify_type(ModuleInfo, Type),
|
|
zero_size_type_category(CtorCat, yes).
|
|
|
|
:- pred zero_size_type_category(type_ctor_category::in, bool::out) is det.
|
|
|
|
zero_size_type_category(CtorCat, ZeroSize) :-
|
|
(
|
|
( CtorCat = ctor_cat_builtin(_)
|
|
; CtorCat = ctor_cat_user(cat_user_direct_dummy)
|
|
; CtorCat = ctor_cat_user(cat_user_abstract_dummy)
|
|
; CtorCat = ctor_cat_void
|
|
; CtorCat = ctor_cat_system(_)
|
|
; CtorCat = ctor_cat_higher_order
|
|
; CtorCat = ctor_cat_enum(_)
|
|
; CtorCat = ctor_cat_builtin_dummy
|
|
),
|
|
ZeroSize = yes
|
|
;
|
|
( CtorCat = ctor_cat_user(cat_user_notag)
|
|
; CtorCat = ctor_cat_user(cat_user_abstract_notag)
|
|
; CtorCat = ctor_cat_user(cat_user_general)
|
|
; CtorCat = ctor_cat_tuple
|
|
; CtorCat = ctor_cat_variable
|
|
),
|
|
ZeroSize = no
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
:- end_module transform_hlds.term_norm.
|
|
%-----------------------------------------------------------------------------%
|