mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
Add the new builtin types: int64 and uint64.
Support for these new types will need to be bootstrapped over several changes.
This is the first such change and does the following:
- Extends the compiler to recognise 'int64' and 'uint64' as builtin types.
- Extends the set of builtin arithmetic, bitwise and relational operators
to cover the new types.
- Adds the new internal option '--unboxed-int64s' to the compiler; this will be
used to control whether 64-bit integer types are boxed or not.
- Extends all of the code generators to handle the new types.
- Extends the runtimes to support the new types.
- Adds new modules to the standard library intend to contain basic operations
on the new types. (These are currently empty and not documented.)
There are bunch of limitations marks with "XXX INT64"; these will be lifted in
part 2 of this change. Also, 64-bit integer types are currently always boxed,
again this limitation will be lifted in later changes.
compiler/options.m:
Add the new option --unboxed-int64s.
compiler/prog_type.m:
compiler/prog_data.m:
compiler/builtin_lib_types.m:
Recognise int64 and uint64 as builtin types.
compiler/builtin_ops.m:
Add builtin operations for the new types.
compiler/hlds_data.m:
Add new tag types for the new types.
compiler/ctgc.selector.m:
compiler/dead_proc_elim.m:
compiler/export.m:
compiler/foreign.m:
compiler/goal_util.m:
compiler/higher_order.m:
compiler/hlds_code_util.m:
compiler/hlds_dependency_graph.m:
compiler/hlds_out_pred.m:
compiler/hlds_out_util.m:
compiler/implementation_defined_literals.m:
compiler/inst_check.m:
compiler/mercury_to_mercury.m:
compiler/mode_util.m:
compiler/module_qual.qualify_items.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/parse_tree_to_term.m:
compiler/parse_type_name.m:
compiler/polymorphism.m:
compiler/prog_out.m:
compiler/prog_util.m:
compiler/rbmm.execution_path.m:
compiler/rtti.m:
compiler/table_gen.m:
compiler/type_util.m:
compiler/typecheck.m:
compiler/unify_gen.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
Conform to the above changes to the parse tree and HLDS.
compiler/c_util.m:
Support writing out constants of the new types.
compiler/llds.m:
Add a representation for constants of the new types to the LLDS.
compiler/stack_layout.m:
Add a new field to the stack layout params that records whether
64-bit integers are boxed or not.
compiler/call_gen.:m
compiler/code_info.m:
compiler/disj_gen.m:
compiler/dupproc.m:
compiler/exprn_aux.m:
compiler/global_data.m:
compiler/jumpopt.m:
compiler/llds_out_data.m:
compiler/llds_out_instr.m:
compiler/lookup_switch.m:
compiler/mercury_compile_llds_back_end.m:
compiler/prog_rep.m:
compiler/prog_rep_tables.m:
compiler/var_locn.m b/compiler/var_locn.m:
Support the new types in the LLDS code generator.
compiler/mlds.m:
Support constants of the new types in the MLDS.
compiler/ml_call_gen.m:
compiler/ml_code_util.m:
compiler/ml_global_data.m:
compiler/ml_rename_classes.m:
compiler/ml_top_gen.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/ml_util.m:
compiler/mlds_to_target_util.m:
compiler/rtti_to_mlds.m:
Conform to the above changes to the MLDS.
compiler/mlds_to_c.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
Generate the appropriate target code for constants of the new types
and operations involving them.
compiler/bytecode.m:
compiler/bytecode_gen.m:
Handle the new types in the bytecode generator; we just abort if we
encounter them for now.
compiler/elds.m:
compiler/elds_to_erlang.m:
compiler/erl_call_gen.m:
compiler/erl_code_util.m:
compiler/erl_unify_gen.m:
Handle the new types in the Erlang code generator.
library/private_builtin.m:
Add placeholders for the builtin unify and compare operations for
the new types. Since the bootstrapping compiler will not recognise
the new types we give them polymorphic arguments. These can be
replaced after this change has bootstrapped.
Update the Java list of TypeCtorRep constants here.
library/int64.m:
library/uint64.m:
New modules that will eventually contain builtin operations on the new
types.
library/library.m:
library/MODULES_UNDOC:
Do not include the above modules in the library documentation for now.
library/construct.m:
library/erlang_rtti_implementation.m:
library/rtti_implementation.m:
library/table_statistics.m:
deep_profiler/program_representation_utils.m:
mdbcomp/program_representation.m:
Handle the new types.
configure.ac:
runtime/mercury_conf.h.in:
Define the macro MR_BOXED_INT64S. For now it is always defined, support for
unboxed 64-bit integers will be enabled in a later change.
runtime/mercury_dotnet.cs.in:
java/runtime/TypeCtorRep.java:
runtime/mercury_type_info.h:
Update the list of type_ctor reps.
runtime/mercury.h:
runtime/mercury_int.[ch]:
Add macros for int64 / uint64 -> MR_Word conversion, boxing and
unboxing.
Add functions for hashing 64-bit integer types suitable for use
with the tabling mechanism.
runtime/mercury_tabling.[ch]:
Add additional HashTableSlot structs for 64-bit integer types.
Omit the '%' character from the conversion specifiers we pass via
the 'key_format' argument to the macros that generate the table lookup
function. This is so we can use the C99 exact size integer conversion
specifiers (e.g. PRIu64 etc.) directly here.
runtime/mercury_hash_lookup_or_add_body.h:
Add the '%' character that was omitted above to the call to debug_key_msg.
runtime/mercury_memory.h:
Add new builtin allocation sites for boxed 64-bit integer types.
runtime/mercury_builtin_types.[ch]:
runtime/mercury_builitn_types_proc_layouts.h:
runtime/mercury_construct.c:
runtime/mercury_deconstruct.c:
runtime/mercury_deep_copy_body.h:
runtime/mercury_ml_expand_body.h:
runtime/mercury_table_type_body.h:
runtime/mercury_tabling_macros.h:
runtime/mercury_tabling_preds.h:
runtime/mercury_term_size.c:
runtime/mercury_unify_compare_body.h:
Add the new builtin types and handle them throughout the runtime.
runtime/Mmakefile:
Add mercury_int.c to the list of .c files.
doc/reference_manual.texi:
Add the new types to the list of reserved type names.
Add the mapping from the new types to their target language types.
These are commented out for now.
1419 lines
50 KiB
Mathematica
1419 lines
50 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-2012 The University of Melbourne.
|
|
% Copyright (C) 2014-2017 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: prog_data.m.
|
|
% Main author: fjh.
|
|
%
|
|
% This module defines the types that represent the most frequently used parts
|
|
% of the parse trees of Mercury programs.
|
|
%
|
|
% The other prog_data_*.m modules define the other parts of the parse tree
|
|
% that are needed after the creation of the HLDS. prog_item.m defines
|
|
% the parts of the tree that are needed *only until* the creation of the HLDS.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module parse_tree.prog_data.
|
|
:- interface.
|
|
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.prim_data.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.prog_item.
|
|
|
|
:- import_module char.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module set.
|
|
:- import_module term.
|
|
:- import_module varset.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Cons ids.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% The representation of cons_ids below is a compromise. The cons_id
|
|
% type must be defined here, in a submodule of parse_tree.m, because
|
|
% it is a component of insts. However, after the program has been read
|
|
% in, the cons_ids cons, int_const, string_const and float_const,
|
|
% which can appear in user programs, may also be augmented by the other
|
|
% cons_ids, which can only be generated by the compiler.
|
|
%
|
|
% The problem is that some of these compiler generated cons_ids
|
|
% refer to procedures, and the natural method of identifying
|
|
% procedures requires the types pred_id and proc_id, defined
|
|
% in hlds_pred.m, which we don't want to import here.
|
|
%
|
|
% We could try to avoid this problem using two different types
|
|
% for cons_ids, one defined here for use in the parse tree and one
|
|
% defined in hlds_data.m for use in the HLDS. We could distinguish
|
|
% the two by having the HLDS cons_id have a definition such as
|
|
% cons_id ---> parse_cons_id(parse_cons_id) ; ...
|
|
% or, alternatively, by making cons_id parametric in the type of
|
|
% constants, and substitute different constant types (since all the
|
|
% cons_ids that refer to HLDS concepts are constants).
|
|
%
|
|
% Using two different types requires a translation from one to the
|
|
% other. While the runtime cost would be acceptable, the cost in code
|
|
% complexity isn't, since the translation isn't confined to
|
|
% make_hlds.m. (I found this out the hard way.) This is especially so
|
|
% if we want to use in each case only the tightest possible type.
|
|
% For example, while construct goals can involve all cons_ids,
|
|
% deconstruct goals and switches can currently involve only the
|
|
% cons_ids that can appear in parse trees.
|
|
%
|
|
% The solution we have chosen is to exploit the fact that pred_ids
|
|
% and proc_ids are integers. Those types are private to hlds_pred.m,
|
|
% but hlds_pred.m also contains functions for translating them to and
|
|
% from the shrouded versions defined below. The next three types are
|
|
% designed to be used in only two ways: for translation to their HLDS
|
|
% equivalents by the unshroud functions in hlds_pred.m, and for
|
|
% printing for diagnostics.
|
|
%
|
|
:- type shrouded_pred_id
|
|
---> shrouded_pred_id(int).
|
|
:- type shrouded_proc_id
|
|
---> shrouded_proc_id(int).
|
|
:- type shrouded_pred_proc_id
|
|
---> shrouded_pred_proc_id(int, int).
|
|
|
|
:- type cons_id
|
|
---> cons(sym_name, arity, type_ctor)
|
|
% Before post-typecheck, the type_ctor field is not meaningful.
|
|
%
|
|
% Before post-typecheck, tuples and characters have this cons_id.
|
|
% For tuples, this will be of the form
|
|
% `cons(unqualified("{}"), Arity, _)',
|
|
% while for characters, this will be of the form
|
|
% `cons(unqualified(Str), 0, _)'
|
|
% where Str = term_io.quoted_char(Char).
|
|
|
|
; tuple_cons(arity)
|
|
|
|
; closure_cons(shrouded_pred_proc_id, lambda_eval_method)
|
|
% Note that a closure_cons represents a closure, not just
|
|
% a code address.
|
|
% XXX We should have a pred_or_func field as well.
|
|
|
|
; int_const(int)
|
|
; uint_const(uint)
|
|
; int8_const(int8)
|
|
; uint8_const(uint8)
|
|
; int16_const(int16)
|
|
; uint16_const(uint16)
|
|
; int32_const(int32)
|
|
; uint32_const(uint32)
|
|
; int64_const(int) % XXX INT64
|
|
; uint64_const(int) % XXX INT64
|
|
; float_const(float)
|
|
; char_const(char)
|
|
; string_const(string)
|
|
|
|
; impl_defined_const(string)
|
|
|
|
; type_ctor_info_const(
|
|
module_name,
|
|
string, % Name of the type constructor.
|
|
int % Its arity.
|
|
)
|
|
; base_typeclass_info_const(
|
|
module_name,
|
|
% Module name of instance declaration (not filled in
|
|
% so that link errors result from overlapping instances).
|
|
|
|
class_id,
|
|
% Class name and arity.
|
|
|
|
int,
|
|
% Class instance.
|
|
|
|
string
|
|
% Encodes the type names and arities of the arguments
|
|
% of the instance declaration.
|
|
)
|
|
|
|
; type_info_cell_constructor(type_ctor)
|
|
; typeclass_info_cell_constructor
|
|
|
|
; type_info_const(int)
|
|
; typeclass_info_const(int)
|
|
|
|
; ground_term_const(int, cons_id)
|
|
|
|
; tabling_info_const(shrouded_pred_proc_id)
|
|
% The address of the static structure that holds information
|
|
% about the table that implements memoization, loop checking
|
|
% or the minimal model semantics for the given procedure.
|
|
|
|
; table_io_entry_desc(shrouded_pred_proc_id)
|
|
% The address of a structure that describes the layout of the
|
|
% answer block used by I/O tabling for declarative debugging.
|
|
|
|
; deep_profiling_proc_layout(shrouded_pred_proc_id).
|
|
% The Proc_Layout structure of a procedure. Its proc_static field
|
|
% is used by deep profiling, as documented in the deep profiling
|
|
% paper.
|
|
|
|
% Describe how a lambda expression is to be evaluated.
|
|
%
|
|
% `normal' is the top-down Mercury execution algorithm.
|
|
%
|
|
:- type lambda_eval_method
|
|
---> lambda_normal.
|
|
|
|
:- func cons_id_dummy_type_ctor = type_ctor.
|
|
|
|
% Are the two cons_ids equivalent, modulo any module qualifications?
|
|
%
|
|
:- pred equivalent_cons_ids(cons_id::in, cons_id::in) is semidet.
|
|
|
|
:- pred cons_id_is_const_struct(cons_id::in, int::out) is semidet.
|
|
|
|
:- implementation.
|
|
|
|
cons_id_dummy_type_ctor = type_ctor(unqualified(""), -1).
|
|
|
|
equivalent_cons_ids(ConsIdA, ConsIdB) :-
|
|
( if
|
|
ConsIdA = cons(SymNameA, ArityA, _),
|
|
ConsIdB = cons(SymNameB, ArityB, _)
|
|
then
|
|
ArityA = ArityB,
|
|
(
|
|
SymNameA = unqualified(Name),
|
|
SymNameB = unqualified(Name)
|
|
;
|
|
SymNameA = unqualified(Name),
|
|
SymNameB = qualified(_, Name)
|
|
;
|
|
SymNameA = qualified(_, Name),
|
|
SymNameB = unqualified(Name)
|
|
;
|
|
SymNameA = qualified(Qualifier, Name),
|
|
SymNameB = qualified(Qualifier, Name)
|
|
)
|
|
else if
|
|
ConsIdA = cons(SymNameA, ArityA, _),
|
|
ConsIdB = tuple_cons(ArityB)
|
|
then
|
|
ArityA = ArityB,
|
|
SymNameA = unqualified("{}")
|
|
else if
|
|
ConsIdA = tuple_cons(ArityA),
|
|
ConsIdB = cons(SymNameB, ArityB, _)
|
|
then
|
|
ArityA = ArityB,
|
|
SymNameB = unqualified("{}")
|
|
else
|
|
ConsIdA = ConsIdB
|
|
).
|
|
|
|
cons_id_is_const_struct(ConsId, ConstNum) :-
|
|
require_complete_switch [ConsId]
|
|
(
|
|
ConsId = type_info_const(ConstNum)
|
|
;
|
|
ConsId = typeclass_info_const(ConstNum)
|
|
;
|
|
ConsId = ground_term_const(ConstNum, _)
|
|
;
|
|
( ConsId = cons(_, _, _)
|
|
; ConsId = tuple_cons(_)
|
|
; ConsId = closure_cons(_, _)
|
|
; ConsId = int_const(_)
|
|
; ConsId = uint_const(_)
|
|
; ConsId = int8_const(_)
|
|
; ConsId = uint8_const(_)
|
|
; ConsId = int16_const(_)
|
|
; ConsId = uint16_const(_)
|
|
; ConsId = int32_const(_)
|
|
; ConsId = uint32_const(_)
|
|
; ConsId = int64_const(_)
|
|
; ConsId = uint64_const(_)
|
|
; ConsId = float_const(_)
|
|
; ConsId = char_const(_)
|
|
; ConsId = string_const(_)
|
|
; ConsId = impl_defined_const(_)
|
|
; ConsId = type_ctor_info_const(_, _, _)
|
|
; ConsId = base_typeclass_info_const(_, _, _, _)
|
|
; ConsId = type_info_cell_constructor(_)
|
|
; ConsId = typeclass_info_cell_constructor
|
|
; ConsId = tabling_info_const(_)
|
|
; ConsId = table_io_entry_desc(_)
|
|
; ConsId = deep_profiling_proc_layout(_)
|
|
),
|
|
fail
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Types.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% This is how types are represented.
|
|
%
|
|
% One day we might allow types to take value parameters, as well as
|
|
% type parameters.
|
|
%
|
|
:- type type_defn
|
|
---> parse_tree_du_type(type_details_du)
|
|
; parse_tree_eqv_type(type_details_eqv)
|
|
; parse_tree_solver_type(type_details_solver)
|
|
; parse_tree_abstract_type(type_details_abstract)
|
|
; parse_tree_foreign_type(type_details_foreign).
|
|
|
|
:- type type_details_du
|
|
---> type_details_du(
|
|
du_ctors :: list(constructor),
|
|
du_user_uc :: maybe(unify_compare),
|
|
du_direct_arg :: maybe(list(sym_name_and_arity))
|
|
).
|
|
|
|
:- type type_details_eqv
|
|
---> type_details_eqv(
|
|
eqv_type :: mer_type
|
|
).
|
|
|
|
:- type type_details_abstract
|
|
---> abstract_type_general
|
|
; abstract_enum_type(int)
|
|
% The abstract type is known to be an enumeration type, requiring
|
|
% the given number of bits required to represent.
|
|
; abstract_solver_type.
|
|
% An abstract solver type.
|
|
|
|
:- type type_details_solver
|
|
---> type_details_solver(
|
|
solver_details :: solver_type_details,
|
|
solver_user_uc :: maybe(unify_compare)
|
|
).
|
|
|
|
:- type type_details_foreign
|
|
---> type_details_foreign(
|
|
foreign_lang_type :: foreign_language_type,
|
|
foreign_user_uc :: maybe(unify_compare),
|
|
foreign_assertions :: foreign_type_assertions
|
|
).
|
|
|
|
% The `is_solver_type' type specifies whether a type is a "solver" type,
|
|
% for which `any' insts are interpreted as "don't know", or a non-solver
|
|
% type for which `any' is the same as `bound(...)'.
|
|
%
|
|
:- type is_solver_type
|
|
---> non_solver_type
|
|
% The inst `any' is always `bound' for this type.
|
|
|
|
; solver_type.
|
|
% The inst `any' is not always `bound' for this type
|
|
% (i.e. the type was declared with `:- solver type ...').
|
|
|
|
% A foreign_language_type represents a type that is defined in a
|
|
% foreign language and accessed in Mercury (most likely through
|
|
% `pragma foreign_type').
|
|
%
|
|
:- type foreign_language_type
|
|
---> c(c_foreign_type)
|
|
; java(java_foreign_type)
|
|
; csharp(csharp_foreign_type)
|
|
; erlang(erlang_foreign_type).
|
|
|
|
:- type c_foreign_type
|
|
---> c_type(
|
|
string % The C type name
|
|
).
|
|
|
|
:- type java_foreign_type
|
|
---> java_type(
|
|
string % The Java type name
|
|
).
|
|
|
|
:- type csharp_foreign_type
|
|
---> csharp_type(
|
|
string % The C# type name
|
|
).
|
|
|
|
:- type erlang_foreign_type
|
|
---> erlang_type. % Erlang is untyped.
|
|
|
|
:- type foreign_type_assertions
|
|
---> foreign_type_assertions(set(foreign_type_assertion)).
|
|
|
|
:- type foreign_type_assertion
|
|
---> foreign_type_can_pass_as_mercury_type
|
|
; foreign_type_stable
|
|
; foreign_type_word_aligned_pointer.
|
|
|
|
:- type constructor
|
|
---> ctor(
|
|
cons_exist :: existq_tvars,
|
|
cons_constraints :: list(prog_constraint),
|
|
% Existential constraints.
|
|
|
|
cons_name :: sym_name,
|
|
% The cons_id should be cons(SymName, Arity, TypeCtor)
|
|
% for user-defined types, and tuple_cons(Arity) for the
|
|
% system-defined tuple types.
|
|
|
|
cons_args :: list(constructor_arg),
|
|
|
|
cons_num_args :: int,
|
|
% We precompute the number of arguments once, to save having
|
|
% to recompute it many times later.
|
|
|
|
cons_context :: prog_context
|
|
).
|
|
|
|
:- type constructor_arg
|
|
---> ctor_arg(
|
|
arg_field_name :: maybe(ctor_field_name),
|
|
arg_type :: mer_type,
|
|
arg_width :: arg_width,
|
|
arg_context :: prog_context
|
|
).
|
|
|
|
:- type ctor_field_name
|
|
---> ctor_field_name(
|
|
sym_name, % The name of the field.
|
|
prog_context % The context of the name in the source.
|
|
).
|
|
|
|
% How much space does a constructor argument occupy in the underlying
|
|
% representation.
|
|
%
|
|
% `full_word' indicates that the argument occupies a single word.
|
|
% This is the usual case.
|
|
%
|
|
% `double_word' indicates that the argument occupies two words.
|
|
% Currently only double-precision floats may do so.
|
|
%
|
|
% `partial_word_begin(Mask)' indicates that the argument is the first of
|
|
% two or more enumeration arguments which share the same word. The argument
|
|
% occupies the lowest bits in the word so no shifting is required. The
|
|
% other arguments can be masked out with the bit-mask `Mask'. The actual
|
|
% number of bits occupied by the argument is `int.log2(Mask + 1)'.
|
|
%
|
|
% `partial_word_shifted(Shift, Mask)' indicates that the argument is one of
|
|
% the subsequent enumeration arguments which share the same word.
|
|
% `Shift' is the non-zero number of bits that the argument value is
|
|
% left-shifted by. `Mask' is the unshifted bit-mask to mask out other
|
|
% arguments.
|
|
%
|
|
:- type arg_width
|
|
---> full_word
|
|
; double_word
|
|
; partial_word_first(int) % mask
|
|
; partial_word_shifted(int, int). % shift, mask
|
|
|
|
% unify_compare gives the user-defined unification and/or comparison
|
|
% predicates for a noncanonical type, if they are known. The value
|
|
% `abstract_noncanonical_type' represents a type whose definition uses
|
|
% the syntax `where type_is_abstract_noncanonical' and has been read
|
|
% from a .int2 file. This means we know that the type has a
|
|
% noncanonical representation, but we don't know what the
|
|
% unification/comparison predicates are.
|
|
%
|
|
:- type unify_compare
|
|
---> unify_compare(
|
|
uc_unify :: maybe(equality_pred),
|
|
uc_compare :: maybe(comparison_pred)
|
|
)
|
|
; abstract_noncanonical_type(is_solver_type).
|
|
|
|
% The `where' attributes of a solver type definition must begin
|
|
% with
|
|
% representation is <<representation type>>,
|
|
% ground is <<ground inst>>,
|
|
% any is <<any inst>>,
|
|
% constraint_store is <<mutable(...) or [mutable(...), ...]>>
|
|
%
|
|
:- type solver_type_details
|
|
---> solver_type_details(
|
|
std_representation_type :: mer_type,
|
|
std_ground_inst :: mer_inst,
|
|
std_any_inst :: mer_inst,
|
|
std_mutable_items :: list(item_mutable_info)
|
|
).
|
|
|
|
% An init_pred specifies the name of an impure user-defined predicate
|
|
% used to initialise solver type values (the compiler will insert calls
|
|
% to this predicate to convert free solver type variables to inst any
|
|
% variables where necessary.)
|
|
%
|
|
:- type init_pred == sym_name.
|
|
|
|
% An equality_pred specifies the name of a user-defined predicate
|
|
% used for equality on a type. See the chapter on them in the
|
|
% Mercury Language Reference Manual.
|
|
%
|
|
:- type equality_pred == sym_name.
|
|
|
|
% The name of a user-defined comparison predicate.
|
|
%
|
|
:- type comparison_pred == sym_name.
|
|
|
|
% Parameters of type definitions.
|
|
%
|
|
:- type type_param == tvar.
|
|
|
|
% Use prog_type.type_to_ctor_and_args to convert a type to a qualified
|
|
% type_ctor and a list of arguments. Use prog_type.construct_type to
|
|
% construct a type from a type_ctor and a list of arguments.
|
|
%
|
|
:- type mer_type
|
|
---> type_variable(tvar, kind)
|
|
% A type variable.
|
|
|
|
; defined_type(sym_name, list(mer_type), kind)
|
|
% A type using a user defined type constructor.
|
|
|
|
; builtin_type(builtin_type)
|
|
% These are all known to have kind `star'.
|
|
|
|
% The above three functors should be kept as the first three, since
|
|
% they will be the most commonly used and therefore we want them to
|
|
% get the primary tags on a 32-bit machine.
|
|
|
|
; tuple_type(list(mer_type), kind)
|
|
% Tuple types.
|
|
|
|
; higher_order_type(
|
|
% A type for higher-order values. The kind is always `star'.
|
|
% For functions the return type is at the end of the list
|
|
% of argument types.
|
|
pred_or_func,
|
|
list(mer_type),
|
|
ho_inst_info,
|
|
purity,
|
|
lambda_eval_method
|
|
)
|
|
|
|
; apply_n_type(tvar, list(mer_type), kind)
|
|
% An apply/N expression. `apply_n(V, [T1, ...], K)'
|
|
% would be the representation of type `V(T1, ...)' with kind K.
|
|
% The list must be non-empty.
|
|
|
|
; kinded_type(mer_type, kind).
|
|
% A type expression with an explicit kind annotation.
|
|
% (These are not yet used.)
|
|
|
|
|
|
% This type enumerates all of the builtin primitive types in Mercury.
|
|
% If you add a new alternative then you may also need to update the
|
|
% following predicates:
|
|
%
|
|
% - parse_type_name.is_known_type_name_args/3
|
|
% - inst_check.check_inst_defn_has_matching_type/7
|
|
% - llds_out_data.output_type_ctor_addr/5
|
|
% - type_util.classify_type_ctor/2
|
|
%
|
|
:- type builtin_type
|
|
---> builtin_type_int(int_type)
|
|
; builtin_type_float
|
|
; builtin_type_string
|
|
; builtin_type_char.
|
|
|
|
:- type int_type
|
|
---> int_type_int
|
|
; int_type_uint
|
|
; int_type_int8
|
|
; int_type_uint8
|
|
; int_type_int16
|
|
; int_type_uint16
|
|
; int_type_int32
|
|
; int_type_uint32
|
|
; int_type_int64
|
|
; int_type_uint64.
|
|
|
|
:- pred is_builtin_type_sym_name(sym_name::in) is semidet.
|
|
|
|
:- pred is_builtin_type_name(string::in) is semidet.
|
|
|
|
:- pred builtin_type_to_string(builtin_type, string).
|
|
:- mode builtin_type_to_string(in, out) is det.
|
|
:- mode builtin_type_to_string(out, in) is semidet.
|
|
|
|
:- pred int_type_to_string(int_type, string).
|
|
:- mode int_type_to_string(in, out) is det.
|
|
:- mode int_type_to_string(out, in) is semidet.
|
|
|
|
:- type type_term == term(tvar_type).
|
|
|
|
:- type tvar_type
|
|
---> type_var.
|
|
|
|
% "tvar" is short for "type variable".
|
|
:- type tvar == var(tvar_type).
|
|
% A set of type variables.
|
|
:- type tvarset == varset(tvar_type).
|
|
|
|
% A renaming or a substitution on type variables.
|
|
:- type tvar_renaming == map(tvar, tvar).
|
|
:- type tsubst == map(tvar, mer_type).
|
|
|
|
:- type type_ctor
|
|
---> type_ctor(sym_name, arity).
|
|
|
|
:- type tvar_name_map == map(string, tvar).
|
|
|
|
% existq_tvars is used to record the set of type variables which are
|
|
% existentially quantified
|
|
%
|
|
:- type existq_tvars == list(tvar).
|
|
|
|
:- type uses_reserved_tag
|
|
---> uses_reserved_tag
|
|
; does_not_use_reserved_tag.
|
|
|
|
:- type uses_reserved_address
|
|
---> uses_reserved_address
|
|
; does_not_use_reserved_address.
|
|
|
|
% Similar to varset.merge_subst but produces a tvar_renaming
|
|
% instead of a substitution, which is more suitable for types.
|
|
%
|
|
:- pred tvarset_merge_renaming(tvarset::in, tvarset::in, tvarset::out,
|
|
tvar_renaming::out) is det.
|
|
|
|
% As above, but behaves like varset.merge_subst_without_names.
|
|
%
|
|
:- pred tvarset_merge_renaming_without_names(tvarset::in, tvarset::in,
|
|
tvarset::out, tvar_renaming::out) is det.
|
|
|
|
:- implementation.
|
|
|
|
is_builtin_type_sym_name(SymName) :-
|
|
SymName = unqualified(Name),
|
|
builtin_type_to_string(_, Name).
|
|
|
|
is_builtin_type_name(Name) :-
|
|
builtin_type_to_string(_, Name).
|
|
|
|
% Please keep this code in sync with int_type_to_string and
|
|
% classify_type_ctor_if_special.
|
|
builtin_type_to_string(builtin_type_int(int_type_int), "int").
|
|
builtin_type_to_string(builtin_type_int(int_type_uint), "uint").
|
|
builtin_type_to_string(builtin_type_int(int_type_int8), "int8").
|
|
builtin_type_to_string(builtin_type_int(int_type_uint8), "uint8").
|
|
builtin_type_to_string(builtin_type_int(int_type_int16), "int16").
|
|
builtin_type_to_string(builtin_type_int(int_type_uint16), "uint16").
|
|
builtin_type_to_string(builtin_type_int(int_type_int32), "int32").
|
|
builtin_type_to_string(builtin_type_int(int_type_uint32), "uint32").
|
|
builtin_type_to_string(builtin_type_int(int_type_int64), "int64").
|
|
builtin_type_to_string(builtin_type_int(int_type_uint64), "uint64").
|
|
builtin_type_to_string(builtin_type_float, "float").
|
|
builtin_type_to_string(builtin_type_string, "string").
|
|
builtin_type_to_string(builtin_type_char, "character").
|
|
|
|
% Please keep this code in sync with builtin_type_to_string and
|
|
% classify_type_ctor_if_special.
|
|
int_type_to_string(int_type_int, "int").
|
|
int_type_to_string(int_type_uint, "uint").
|
|
int_type_to_string(int_type_int8, "int8").
|
|
int_type_to_string(int_type_uint8, "uint8").
|
|
int_type_to_string(int_type_int16, "int16").
|
|
int_type_to_string(int_type_uint16, "uint16").
|
|
int_type_to_string(int_type_int32, "int32").
|
|
int_type_to_string(int_type_uint32, "uint32").
|
|
int_type_to_string(int_type_int64, "int64").
|
|
int_type_to_string(int_type_uint64, "uint64").
|
|
|
|
tvarset_merge_renaming(TVarSetA, TVarSetB, TVarSet, Renaming) :-
|
|
varset.merge_renaming(TVarSetA, TVarSetB, TVarSet, Renaming).
|
|
|
|
tvarset_merge_renaming_without_names(TVarSetA, TVarSetB, TVarSet, Renaming) :-
|
|
varset.merge_renaming_without_names(TVarSetA, TVarSetB, TVarSet, Renaming).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Kinds.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% Note that we don't support any kind other than `star' at the moment.
|
|
% The other kinds are intended for the implementation of constructor
|
|
% classes.
|
|
%
|
|
:- type kind
|
|
---> kind_star
|
|
% An ordinary type.
|
|
|
|
; kind_arrow(kind, kind)
|
|
% A type with kind `A' applied to a type with kind `arrow(A, B)'
|
|
% will have kind `B'.
|
|
|
|
; kind_variable(kvar).
|
|
% A kind variable. These can be used during kind inference;
|
|
% after kind inference, all remaining kind variables will be
|
|
% bound to `star'.
|
|
|
|
:- type kvar_type
|
|
---> kind_var.
|
|
:- type kvar == var(kvar_type).
|
|
|
|
% The kinds of type variables. For efficiency, we only have entries
|
|
% for type variables that have a kind other than `star'. Any type variable
|
|
% not appearing in this map, which will usually be the majority of type
|
|
% variables, can be assumed to have kind `star'.
|
|
%
|
|
:- type tvar_kind_map == map(tvar, kind).
|
|
|
|
:- pred get_tvar_kind(tvar_kind_map::in, tvar::in, kind::out) is det.
|
|
|
|
% Return the kind of a type.
|
|
%
|
|
:- func get_type_kind(mer_type) = kind.
|
|
|
|
:- implementation.
|
|
|
|
get_tvar_kind(Map, TVar, Kind) :-
|
|
( if map.search(Map, TVar, Kind0) then
|
|
Kind = Kind0
|
|
else
|
|
Kind = kind_star
|
|
).
|
|
|
|
get_type_kind(type_variable(_, Kind)) = Kind.
|
|
get_type_kind(defined_type(_, _, Kind)) = Kind.
|
|
get_type_kind(builtin_type(_)) = kind_star.
|
|
get_type_kind(higher_order_type(_, _, _, _, _)) = kind_star.
|
|
get_type_kind(tuple_type(_, Kind)) = Kind.
|
|
get_type_kind(apply_n_type(_, _, Kind)) = Kind.
|
|
get_type_kind(kinded_type(_, Kind)) = Kind.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Type classes.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% A class constraint represents a constraint that a given list of types
|
|
% is a member of the specified type class. It is an invariant of this data
|
|
% structure that the types in a class constraint do not contain any
|
|
% information in their prog_context fields. This invariant is needed
|
|
% to ensure that we can do unifications, map.lookups, etc., and get the
|
|
% expected semantics. (This invariant now applies to all types, but is
|
|
% especially important here.)
|
|
%
|
|
% Values of type prog_constraint are used as keys in several maps;
|
|
% currently (december 2014) these are represented by the types
|
|
% ancestor_constraints, constraint_proof_map and typeclass_info_varmap.
|
|
% We cannot store the context of each constraint in here, since after
|
|
% we have put a constraint into one of these maps with one context,
|
|
% we wouldn't find it if searching for it with another context, which
|
|
% would thus defeat the purpose of those maps (to find common uses
|
|
% of the same constraint).
|
|
%
|
|
:- type prog_constraint
|
|
---> constraint(
|
|
constraint_class :: class_name,
|
|
constraint_arg_types :: list(mer_type)
|
|
).
|
|
|
|
:- type prog_constraints
|
|
---> constraints(
|
|
univ_constraints :: list(prog_constraint),
|
|
% Universally quantified constraints.
|
|
exist_constraints :: list(prog_constraint)
|
|
% Existentially quantified constraints.
|
|
).
|
|
|
|
% A functional dependency on the variables in the head of a class
|
|
% declaration. This asserts that, given the complete set of instances
|
|
% of this class, the binding of the range variables can be uniquely
|
|
% determined from the binding of the domain variables.
|
|
%
|
|
% XXX Both lists should be one_or_more(tvar).
|
|
%
|
|
:- type prog_fundep
|
|
---> fundep(
|
|
domain :: list(tvar),
|
|
range :: list(tvar)
|
|
).
|
|
|
|
:- type class_name == sym_name.
|
|
:- type class_id
|
|
---> class_id(class_name, arity).
|
|
|
|
:- type class_interface
|
|
---> class_interface_abstract
|
|
; class_interface_concrete(list(class_method)).
|
|
|
|
:- type instance_method
|
|
---> instance_method(
|
|
instance_method_p_or_f :: pred_or_func,
|
|
instance_method_name :: sym_name,
|
|
instance_method_proc_def :: instance_proc_def,
|
|
instance_method_arity :: arity,
|
|
|
|
instance_method_decl_context :: prog_context
|
|
% The context of the instance declaration.
|
|
).
|
|
|
|
:- type instance_proc_def
|
|
---> instance_proc_def_name(
|
|
% defined using the `pred(...) is <Name>' syntax
|
|
sym_name
|
|
)
|
|
; instance_proc_def_clauses(
|
|
% defined using clauses
|
|
list(item_clause_info)
|
|
).
|
|
|
|
:- type instance_body
|
|
---> instance_body_abstract
|
|
; instance_body_concrete(list(instance_method)).
|
|
|
|
:- func prog_constraint_get_class(prog_constraint) = class_name.
|
|
:- func prog_constraint_get_arg_types(prog_constraint) = list(mer_type).
|
|
|
|
:- type maybe_class_method
|
|
---> is_not_a_class_method
|
|
; is_a_class_method.
|
|
|
|
:- implementation.
|
|
|
|
prog_constraint_get_class(Constraint) = Constraint ^ constraint_class.
|
|
prog_constraint_get_arg_types(Constraint) = Constraint ^ constraint_arg_types.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Insts and modes.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% This is how instantiatednesses and modes are represented.
|
|
%
|
|
:- type mer_inst
|
|
---> free
|
|
; free(mer_type)
|
|
|
|
; any(uniqueness, ho_inst_info)
|
|
% The ho_inst_info holds extra information
|
|
% about higher-order values.
|
|
|
|
; bound(uniqueness, inst_test_results, list(bound_inst))
|
|
% The list(bound_inst) must be sorted.
|
|
|
|
; ground(uniqueness, ho_inst_info)
|
|
% The ho_inst_info holds extra information
|
|
% about higher-order values.
|
|
|
|
; not_reached
|
|
; inst_var(inst_var)
|
|
|
|
; constrained_inst_vars(set(inst_var), mer_inst)
|
|
% Constrained_inst_vars is a set of inst variables that are
|
|
% constrained to have the same uniqueness as and to match_final
|
|
% the specified inst.
|
|
|
|
; defined_inst(inst_name)
|
|
% A defined_inst is possibly recursive inst whose value is
|
|
% stored in the inst_table. This is used both for user-defined
|
|
% insts and for compiler-generated insts.
|
|
|
|
; abstract_inst(sym_name, list(mer_inst)).
|
|
% An abstract inst is a defined inst which has been declared
|
|
% but not actually been defined (yet).
|
|
|
|
:- inst mer_inst_is_bound for mer_inst/0
|
|
---> bound(ground, ground, ground).
|
|
|
|
% Values of this type give the outcome of various tests on an inst,
|
|
% if that information is available when the inst is constructed.
|
|
% The purpose is to allow those tests to work in constant time,
|
|
% not time that is linear, quadratic or worse in the size of the inst.
|
|
%
|
|
% We attach this information to bound insts, since the only practical
|
|
% way to make an inst big is to use bound insts.
|
|
%
|
|
% We could extend the number of tests whose results we can record,
|
|
% but we should do so only when we have a demonstrated need, and I (zs)
|
|
% don't yet see the need for them. However, here is a list of the tests
|
|
% whose results we can consider adding, together with the names of the
|
|
% predicates that could use them.
|
|
%
|
|
% Does the inst contain a nondefault func mode?
|
|
% inst_contains_nondefault_func_mode
|
|
%
|
|
% Does the inst contain any part that is uniq or mostly_uniq?
|
|
% make_shared_inst
|
|
%
|
|
:- type inst_test_results
|
|
---> inst_test_results(
|
|
inst_result_groundness,
|
|
inst_result_contains_any,
|
|
inst_result_contains_inst_names,
|
|
inst_result_contains_inst_vars,
|
|
inst_result_contains_types,
|
|
inst_result_type_ctor_propagated
|
|
)
|
|
; inst_test_no_results
|
|
% Implies
|
|
% inst_result_groundness_unknown
|
|
% inst_result_contains_any_unknown
|
|
% inst_result_contains_inst_names_unknown
|
|
% inst_result_contains_inst_vars_unknown
|
|
% inst_result_contains_types_unknown
|
|
% inst_result_no_type_ctor_propagated
|
|
; inst_test_results_fgtc.
|
|
% Implies
|
|
% inst_result_is_ground
|
|
% inst_result_does_not_contain_any
|
|
% inst_result_contains_inst_names_known(set.init)
|
|
% inst_result_contains_inst_vars_known(set.init)
|
|
% inst_result_contains_types_known(set.init)
|
|
% inst_result_no_type_ctor_propagated
|
|
% It also implies that the inst does not contain any
|
|
% typed insts, constrained insts or higher order type insts,
|
|
% and that no part of it is unique or mostly_unique.
|
|
|
|
% Does the inst represent a ground term?
|
|
:- type inst_result_groundness
|
|
---> inst_result_is_not_ground
|
|
; inst_result_is_ground
|
|
; inst_result_groundness_unknown.
|
|
|
|
% Does "any" appear anywhere inside the inst?
|
|
:- type inst_result_contains_any
|
|
---> inst_result_does_not_contain_any
|
|
; inst_result_does_contain_any
|
|
; inst_result_contains_any_unknown.
|
|
|
|
:- type inst_result_contains_inst_names
|
|
---> inst_result_contains_inst_names_known(set(inst_name))
|
|
% All the inst_names inside the inst are given in the set.
|
|
% This is not a guarantee that all the inst_names in the set
|
|
% appear in the inst, but it is a guarantee that an inst_name
|
|
% that appears in the inst will appear in the set.
|
|
; inst_result_contains_inst_names_unknown.
|
|
|
|
:- type inst_result_contains_inst_vars
|
|
---> inst_result_contains_inst_vars_known(set(inst_var))
|
|
% All the inst_vars inside the inst are given in the set.
|
|
% This is not a guarantee that all the inst_vars in the set
|
|
% appear in the inst, but it is a guarantee that an inst_var
|
|
% that appears in the inst will appear in the set.
|
|
; inst_result_contains_inst_vars_unknown.
|
|
|
|
:- type inst_result_contains_types
|
|
---> inst_result_contains_types_known(set(type_ctor))
|
|
% All the type_ctors inside typed_inst nodes of the inst
|
|
% are given in the set. This is not a guarantee that all the
|
|
% type_ctors in the set appear in the inst, but it is a guarantee
|
|
% that a type_ctor that appears in the inst will appear in the set.
|
|
; inst_result_contains_types_unknown.
|
|
|
|
:- type inst_result_type_ctor_propagated
|
|
---> inst_result_no_type_ctor_propagated
|
|
% The inst is not known to have had a type_ctor propagated
|
|
% into it.
|
|
; inst_result_type_ctor_propagated(type_ctor).
|
|
% The inst has had the given type_ctor propagated into it.
|
|
% The type_ctor must have arity 0, since otherwise the propagation
|
|
% code wouldn't know what type to propagate into the arguments.
|
|
% (We could record a full type being propagated into the inst,
|
|
% complete with type_ctor arguments, but that couldn't be
|
|
% pre-propagated in inst_user.m in vast majority of cases
|
|
% in which the argument types are not available.)
|
|
|
|
:- type uniqueness
|
|
---> shared
|
|
% There might be other references.
|
|
|
|
; unique
|
|
% There is only one reference.
|
|
|
|
; mostly_unique
|
|
% There is only one reference, but there might be more
|
|
% on backtracking.
|
|
|
|
; clobbered
|
|
% This was the only reference, but the data has
|
|
% already been reused.
|
|
|
|
; mostly_clobbered.
|
|
% This was the only reference, but the data has already
|
|
% been reused; however, there may be more references
|
|
% on backtracking, so we will need to restore the old value
|
|
% on backtracking.
|
|
|
|
% Was the lambda goal created with pred/func or any_pred/any_func?
|
|
%
|
|
:- type ho_groundness
|
|
---> ho_ground
|
|
; ho_any.
|
|
|
|
% The ho_inst_info type gives extra information about `ground' and `any'
|
|
% insts relating to higher-order values.
|
|
%
|
|
:- type ho_inst_info
|
|
---> higher_order(pred_inst_info)
|
|
% The inst is higher-order, and we have mode/determinism
|
|
% information for the value.
|
|
; none_or_default_func.
|
|
% No extra information is available, or the inst is function
|
|
% with the default mode.
|
|
|
|
% higher-order predicate terms are given the inst
|
|
% `ground(shared, higher_order(PredInstInfo))' or
|
|
% `any(shared, higher_order(PredInstInfo))'
|
|
% where the PredInstInfo contains the extra modes and the determinism
|
|
% for the predicate. The higher-order predicate term itself cannot be free.
|
|
% If it contains non-local variables with inst `any' then it must be
|
|
% in the latter form, otherwise it may be in the former.
|
|
%
|
|
% Note that calling/applying a higher-order value that has the `any'
|
|
% inst may bind that variable further, hence these values cannot safely
|
|
% be called/applied in a negated context.
|
|
%
|
|
:- type pred_inst_info
|
|
---> pred_inst_info(
|
|
% Is this a higher-order func mode or a higher-order pred mode?
|
|
pred_or_func,
|
|
|
|
% The modes of the additional (i.e. not-yet-supplied) arguments
|
|
% of the pred; for a function, this includes the mode of the
|
|
% return value as the last element of the list.
|
|
list(mer_mode),
|
|
|
|
% The register type to use for each of the additional arguments
|
|
% of the pred. This field is only needed when float registers
|
|
% exist, and is only set after the float reg wrappers pass.
|
|
arg_reg_type_info,
|
|
|
|
% The determinism of the predicate or function.
|
|
determinism
|
|
).
|
|
|
|
:- type arg_reg_type_info
|
|
---> arg_reg_types_unset % Unneeded or simply unset yet.
|
|
; arg_reg_types(list(ho_arg_reg)).
|
|
|
|
:- type ho_arg_reg
|
|
---> ho_arg_reg_r
|
|
; ho_arg_reg_f.
|
|
|
|
:- type inst_id
|
|
---> inst_id(sym_name, arity).
|
|
|
|
:- type bound_inst
|
|
---> bound_functor(cons_id, list(mer_inst)).
|
|
|
|
:- type inst_var_type
|
|
---> inst_var_type.
|
|
|
|
:- type inst_var == var(inst_var_type).
|
|
:- type inst_term == term(inst_var_type).
|
|
:- type inst_varset == varset(inst_var_type).
|
|
|
|
:- type head_inst_vars == map(inst_var, mer_inst).
|
|
:- type inst_var_sub == map(inst_var, mer_inst).
|
|
|
|
% inst_defn/5 is defined in prog_item.m.
|
|
|
|
:- type inst_defn
|
|
---> eqv_inst(mer_inst)
|
|
; abstract_inst.
|
|
|
|
% An `inst_name' is used as a key for the inst_table.
|
|
% It is either a user-defined inst `user_inst(Name, Args)',
|
|
% or some sort of compiler-generated inst, whose name
|
|
% is a representation of its meaning.
|
|
%
|
|
% For example, `merge_inst(InstA, InstB)' is the name used for the
|
|
% inst that results from merging InstA and InstB using `merge_inst'.
|
|
% Similarly `unify_inst(IsLive, InstA, InstB, IsReal)' is
|
|
% the name for the inst that results from a call to
|
|
% `abstractly_unify_inst(IsLive, InstA, InstB, IsReal)'.
|
|
% And `ground_inst' and `any_inst' are insts that result
|
|
% from unifying an inst with `ground' or `any', respectively.
|
|
% `typed_inst' is an inst with added type information.
|
|
% `typed_ground(Uniq, Type)' a equivalent to
|
|
% `typed_inst(ground(Uniq, no), Type)'.
|
|
% Note that `typed_ground' is a special case of `typed_inst',
|
|
% and `ground_inst' and `any_inst' are special cases of `unify_inst'.
|
|
% The reason for having the special cases is efficiency.
|
|
%
|
|
:- type inst_name
|
|
---> user_inst(sym_name, list(mer_inst))
|
|
; unify_inst(is_live, unify_is_real, mer_inst, mer_inst)
|
|
; merge_inst(mer_inst, mer_inst)
|
|
; ground_inst(inst_name, uniqueness, is_live, unify_is_real)
|
|
; any_inst(inst_name, uniqueness, is_live, unify_is_real)
|
|
; shared_inst(inst_name)
|
|
; mostly_uniq_inst(inst_name)
|
|
; typed_ground(uniqueness, mer_type)
|
|
; typed_inst(mer_type, inst_name).
|
|
|
|
:- type unify_inst_info
|
|
---> unify_inst_info(is_live, unify_is_real, mer_inst, mer_inst).
|
|
:- type merge_inst_info
|
|
---> merge_inst_info(mer_inst, mer_inst).
|
|
:- type ground_inst_info
|
|
---> ground_inst_info(inst_name, uniqueness, is_live, unify_is_real).
|
|
:- type any_inst_info
|
|
---> any_inst_info(inst_name, uniqueness, is_live, unify_is_real).
|
|
|
|
% NOTE: `is_live' records liveness in the sense used by mode analysis.
|
|
% This is not the same thing as the notion of liveness used by code
|
|
% generation. See compiler/notes/glossary.html.
|
|
%
|
|
:- type is_live
|
|
---> is_live
|
|
; is_dead.
|
|
|
|
% Unifications of insts fall into two categories, "real" and "fake".
|
|
% The "real" inst unifications correspond to real unifications,
|
|
% and are not allowed to unify with `clobbered' insts (unless
|
|
% the unification would be `det').
|
|
% Any inst unification which is associated with some code that
|
|
% will actually examine the contents of the variables in question
|
|
% must be "real". Inst unifications that are not associated with
|
|
% some real code that examines the variables' values are "fake".
|
|
% "Fake" inst unifications are used for procedure calls in implied
|
|
% modes, where the final inst of the var must be computed by
|
|
% unifying its initial inst with the procedure's final inst,
|
|
% so that if you pass a ground var to a procedure whose mode
|
|
% is `free -> list_skeleton', the result is ground, not list_skeleton.
|
|
% But these fake unifications must be allowed to unify with `clobbered'
|
|
% insts. Hence we pass down a flag to `abstractly_unify_inst' which
|
|
% specifies whether or not to allow unifications with clobbered values.
|
|
%
|
|
:- type unify_is_real
|
|
---> real_unify
|
|
; fake_unify.
|
|
|
|
:- type mode_id
|
|
---> mode_id(sym_name, arity).
|
|
|
|
:- type mode_defn
|
|
---> eqv_mode(mer_mode).
|
|
|
|
:- type mer_mode
|
|
---> from_to_mode(mer_inst, mer_inst)
|
|
; user_defined_mode(sym_name, list(mer_inst)).
|
|
|
|
:- type from_to_insts
|
|
---> from_to_insts(mer_inst, mer_inst).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Determinism.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% The `determinism' type specifies how many solutions a given procedure
|
|
% may have.
|
|
%
|
|
:- type determinism
|
|
---> detism_det
|
|
; detism_semi
|
|
; detism_multi
|
|
; detism_non
|
|
; detism_cc_multi
|
|
; detism_cc_non
|
|
; detism_erroneous
|
|
; detism_failure.
|
|
|
|
:- type can_fail
|
|
---> can_fail
|
|
; cannot_fail.
|
|
|
|
:- type soln_count
|
|
---> at_most_zero
|
|
; at_most_one
|
|
; at_most_many_cc
|
|
% "_cc" means "committed-choice": there is more than one logical
|
|
% solution, but the pred or goal is being used in a context where
|
|
% we are only looking for the first solution.
|
|
; at_most_many.
|
|
|
|
:- pred determinism_components(determinism, can_fail, soln_count).
|
|
:- mode determinism_components(in, out, out) is det.
|
|
:- mode determinism_components(out, in, in) is det.
|
|
|
|
:- implementation.
|
|
|
|
determinism_components(detism_det, cannot_fail, at_most_one).
|
|
determinism_components(detism_semi, can_fail, at_most_one).
|
|
determinism_components(detism_multi, cannot_fail, at_most_many).
|
|
determinism_components(detism_non, can_fail, at_most_many).
|
|
determinism_components(detism_cc_multi, cannot_fail, at_most_many_cc).
|
|
determinism_components(detism_cc_non, can_fail, at_most_many_cc).
|
|
determinism_components(detism_erroneous, cannot_fail, at_most_zero).
|
|
determinism_components(detism_failure, can_fail, at_most_zero).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Purity.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% Purity indicates whether a goal can have side effects or can depend on
|
|
% global state. See purity.m and the "Purity" section of the Mercury
|
|
% language reference manual.
|
|
:- type purity
|
|
---> purity_pure
|
|
; purity_semipure
|
|
; purity_impure.
|
|
|
|
% Compare two purities.
|
|
%
|
|
:- pred less_pure(purity::in, purity::in) is semidet.
|
|
|
|
% Sort of a "maximum" for impurity.
|
|
%
|
|
:- func worst_purity(purity, purity) = purity.
|
|
|
|
% Sort of a "minimum" for impurity.
|
|
%
|
|
:- func best_purity(purity, purity) = purity.
|
|
|
|
:- implementation.
|
|
|
|
less_pure(P1, P2) :-
|
|
worst_purity(P1, P2) \= P2.
|
|
|
|
% worst_purity/3 could be written more compactly, but this definition
|
|
% guarantees us a determinism error if we add to type `purity'. We also
|
|
% define less_pure/2 in terms of worst_purity/3 rather than the other way
|
|
% around for the same reason.
|
|
%
|
|
worst_purity(purity_pure, purity_pure) = purity_pure.
|
|
worst_purity(purity_pure, purity_semipure) = purity_semipure.
|
|
worst_purity(purity_pure, purity_impure) = purity_impure.
|
|
worst_purity(purity_semipure, purity_pure) = purity_semipure.
|
|
worst_purity(purity_semipure, purity_semipure) = purity_semipure.
|
|
worst_purity(purity_semipure, purity_impure) = purity_impure.
|
|
worst_purity(purity_impure, purity_pure) = purity_impure.
|
|
worst_purity(purity_impure, purity_semipure) = purity_impure.
|
|
worst_purity(purity_impure, purity_impure) = purity_impure.
|
|
|
|
% best_purity/3 is written as a switch for the same reason as
|
|
% worst_purity/3.
|
|
%
|
|
best_purity(purity_pure, purity_pure) = purity_pure.
|
|
best_purity(purity_pure, purity_semipure) = purity_pure.
|
|
best_purity(purity_pure, purity_impure) = purity_pure.
|
|
best_purity(purity_semipure, purity_pure) = purity_pure.
|
|
best_purity(purity_semipure, purity_semipure) = purity_semipure.
|
|
best_purity(purity_semipure, purity_impure) = purity_semipure.
|
|
best_purity(purity_impure, purity_pure) = purity_pure.
|
|
best_purity(purity_impure, purity_semipure) = purity_semipure.
|
|
best_purity(purity_impure, purity_impure) = purity_impure.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Goals.
|
|
%
|
|
%
|
|
% NOTE The representation of goals in the parse tree is defined in
|
|
% prog_item.m, because goals in the parse tree don't *themselves* survive
|
|
% being translated into HLDS. However, some of their *components* do survive.
|
|
% The following types define these components.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% These type equivalences are for the types of program variables
|
|
% and associated structures.
|
|
%
|
|
:- type prog_var_type
|
|
---> prog_var_type.
|
|
:- type prog_var == var(prog_var_type).
|
|
:- type prog_varset == varset(prog_var_type).
|
|
:- type prog_substitution == substitution(prog_var_type).
|
|
:- type prog_var_renaming == map(prog_var, prog_var).
|
|
:- type prog_term == term(prog_var_type).
|
|
:- type prog_vars == list(prog_var).
|
|
|
|
% What to print when printing variable names.
|
|
% You can get the effect of printing variable numbers only
|
|
% by passing an empty varset, which effectively makes *all* variables
|
|
% unnamed, but having an explicit option for this is more readable.
|
|
:- type var_name_print
|
|
---> print_name_only
|
|
; print_name_and_num
|
|
; print_num_only.
|
|
|
|
:- type prog_context == term.context.
|
|
|
|
:- type trace_expr(Base)
|
|
---> trace_base(Base)
|
|
; trace_not(trace_expr(Base))
|
|
; trace_op(trace_op, trace_expr(Base), trace_expr(Base)).
|
|
|
|
:- type trace_op
|
|
---> trace_or
|
|
; trace_and.
|
|
|
|
:- type trace_compiletime
|
|
---> trace_flag(string)
|
|
; trace_grade(trace_grade)
|
|
; trace_trace_level(trace_trace_level).
|
|
|
|
:- type trace_grade
|
|
---> trace_grade_debug
|
|
; trace_grade_ssdebug
|
|
; trace_grade_prof
|
|
; trace_grade_profdeep
|
|
; trace_grade_par
|
|
; trace_grade_trail
|
|
; trace_grade_rbmm
|
|
; trace_grade_llds
|
|
; trace_grade_mlds
|
|
; trace_grade_c
|
|
; trace_grade_csharp
|
|
; trace_grade_java
|
|
; trace_grade_erlang.
|
|
|
|
:- type trace_trace_level
|
|
---> trace_level_shallow
|
|
; trace_level_deep.
|
|
|
|
:- type trace_runtime
|
|
---> trace_envvar(string).
|
|
|
|
:- type trace_mutable_var
|
|
---> trace_mutable_var(
|
|
trace_mutable_name :: string,
|
|
trace_state_var :: prog_var
|
|
).
|
|
|
|
:- type atomic_component_state
|
|
---> atomic_state_var(prog_var)
|
|
; atomic_var_pair(prog_var, prog_var).
|
|
|
|
:- pred parse_trace_grade_name(string, trace_grade).
|
|
:- mode parse_trace_grade_name(in, out) is semidet.
|
|
:- mode parse_trace_grade_name(out, in) is det.
|
|
:- mode parse_trace_grade_name(out, out) is multi.
|
|
|
|
:- pred valid_trace_grade_name(string::out) is multi.
|
|
|
|
% Values of this type are part of the representation
|
|
% of the disable_warnings scope.
|
|
:- type goal_warning
|
|
---> goal_warning_singleton_vars
|
|
; goal_warning_non_tail_recursive_calls.
|
|
|
|
:- implementation.
|
|
|
|
% If you update this, you also need to update the corresponding section
|
|
% of doc/reference_manual.texi.
|
|
parse_trace_grade_name("debug", trace_grade_debug).
|
|
parse_trace_grade_name("ssdebug", trace_grade_ssdebug).
|
|
parse_trace_grade_name("prof", trace_grade_prof).
|
|
parse_trace_grade_name("profdeep", trace_grade_profdeep).
|
|
parse_trace_grade_name("par", trace_grade_par).
|
|
parse_trace_grade_name("trail", trace_grade_trail).
|
|
parse_trace_grade_name("rbmm", trace_grade_rbmm).
|
|
parse_trace_grade_name("llds", trace_grade_llds).
|
|
parse_trace_grade_name("mlds", trace_grade_mlds).
|
|
parse_trace_grade_name("c", trace_grade_c).
|
|
parse_trace_grade_name("csharp", trace_grade_csharp).
|
|
parse_trace_grade_name("java", trace_grade_java).
|
|
parse_trace_grade_name("erlang", trace_grade_erlang).
|
|
|
|
valid_trace_grade_name(GradeName) :-
|
|
parse_trace_grade_name(GradeName, _).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Trailing and minimal model tabling analysis.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
:- type trailing_status
|
|
---> trail_may_modify
|
|
; trail_will_not_modify
|
|
; trail_conditional.
|
|
|
|
:- type mm_tabling_status
|
|
---> mm_tabled_may_call
|
|
; mm_tabled_will_not_call
|
|
; mm_tabled_conditional.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Parts of items that are needed beyond the construction of the HLDS.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
% What kind of promise does a promise item contain?
|
|
%
|
|
:- type promise_type
|
|
% promise ex declarations
|
|
---> promise_type_exclusive
|
|
% Each disjunct is mutually exclusive.
|
|
|
|
; promise_type_exhaustive
|
|
% Disjunction cannot fail.
|
|
|
|
; promise_type_exclusive_exhaustive
|
|
% Both of the above assertions
|
|
|
|
; promise_type_true.
|
|
% Promise goal is true.
|
|
|
|
% A predicate or function declaration may either give (a) only the types
|
|
% of the arguments, or (b) both their types and modes.
|
|
:- type type_and_mode
|
|
---> type_only(mer_type)
|
|
; type_and_mode(mer_type, mer_mode).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Module system.
|
|
%
|
|
|
|
:- interface.
|
|
|
|
:- type sym_name_specifier
|
|
---> sym_name_specifier_name(sym_name)
|
|
; sym_name_specifier_name_arity(sym_name, arity).
|
|
|
|
:- type sym_name_and_arity
|
|
---> sym_name_arity(sym_name, arity).
|
|
|
|
:- type simple_call_id
|
|
---> simple_call_id(pred_or_func, sym_name, arity).
|
|
|
|
:- type arity == int.
|
|
|
|
% Describes whether an item can be used without an explicit module
|
|
% qualifier.
|
|
%
|
|
:- type need_qualifier
|
|
---> must_be_qualified
|
|
; may_be_unqualified.
|
|
|
|
% Does a module contain the predicate main/2?
|
|
%
|
|
:- type has_main
|
|
---> has_main
|
|
; no_main.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module parse_tree.prog_data.
|
|
%---------------------------------------------------------------------------%
|