mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
Estimated hours taken: 60 User-guided type specialization. compiler/prog_data.m: compiler/prog_io_pragma.m: compiler/modules.m: compiler/module_qual.m: compiler/mercury_to_mercury.m: Handle `:- pragma type_spec'. compiler/prog_io_pragma.m: Factor out some common code to parse predicate names with arguments. compiler/hlds_module.m: Added a field to the module_sub_info to hold information about user-requested type specializations, filled in by make_hlds.m and not used by anything after higher_order.m. compiler/make_hlds.m: For each `:- pragma type_spec' declaration, introduce a new predicate which just calls the predicate to be specialized with the specified argument types. This forces higher_order.m to produce the specialized versions. compiler/higher_order.m: Process the user-requested type specializations first to ensure that they get the correct names. Allow partial matches against user-specified versions, e.g. map__lookup(map(int, list(int)), int, list(int)) matches map__lookup(map(int, V), int, V). Perform specialization where a typeclass constraint matches a known instance, but the construction of the typeclass_info is done in the calling module. Give slightly more informative progress messages. compiler/dead_proc_elim.m: Remove specializations for dead procedures. compiler/prog_io_util.m: Change the definition of the `maybe1' and `maybe_functor' types to avoid the need for copying to convert between `maybe1' and `maybe1(generic)'. Changed the interface of `make_pred_name_with_context' to allow creation of predicate names for type specializations which describe the type substitution. compiler/make_hlds.m: compiler/prog_io_pragma.m: Make the specification of pragma declarations in error messages consistent. (There are probably some more to be fixed elsewhere for termination and tabling). compiler/intermod.m: Write type specialization pragmas for predicates declared in `.opt' files. compiler/mercury_to_mercury.m: Export `mercury_output_item' for use by intermod.m. compiler/options.m: Add an option `--user-guided-type-specialization' enabled with `-O2' or higher. compiler/handle_options.m: `--type-specialization' implies `--user-guided-type-specialization'. compiler/hlds_goal.m: Add predicates to construct constants. These are duplicated in several other places, I'll fix that as a separate change. compiler/type_util.m: Added functions `int_type/0', `string_type/0', `float_type/0' and `char_type/0' which return the builtin types. These are duplicated in several other places, I'll fix that as a separate change. library/private_builtin.m: Added `instance_constraint_from_typeclass_info/3' to extract the typeclass_infos for a constraint on an instance declaration. This is useful for specializing class method calls. Added `thread_safe' to various `:- pragma c_code's. Added `:- pragma inline' declarations for `builtin_compare_*', which are important for user-guided type specialization. (`builtin_unify_*' are simple enough to go in the `.opt' files automatically). compiler/polymorphism.m: `instance_constraint_from_typeclass_info/3' does not need type_infos. Add `instance_constraint_from_typeclass_info/3' to the list of `typeclass_info_manipulator's which higher_order.m can interpret. NEWS: doc/reference_manual.texi: doc/user_guide.texi Document the new pragma and option. tests/invalid/Mmakefile: tests/invalid/type_spec.m: tests/invalid/type_spec.err_exp: Test error reporting for invalid type specializations. tests/hard_coded/Mmakefile: tests/invalid/type_spec.m: tests/invalid/type_spec.exp: Test type specialization.
744 lines
23 KiB
Mathematica
744 lines
23 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1996-1999 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: prog_data.m.
|
|
% Main author: fjh.
|
|
%
|
|
% This module defines a data structure for representing Mercury programs.
|
|
%
|
|
% This data structure specifies basically the same information as is
|
|
% contained in the source code, but in a parse tree rather than a flat file.
|
|
% Simplifications are done only by make_hlds.m, which transforms
|
|
% the parse tree which we built here into the HLDS.
|
|
|
|
:- module prog_data.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_data, hlds_pred, (inst), purity, rl, term_util.
|
|
:- import_module assoc_list, list, map, varset, term, std_util.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This is how programs (and parse errors) are represented.
|
|
|
|
:- type message_list == list(pair(string, term)).
|
|
% the error/warning message, and the
|
|
% term to which it relates
|
|
|
|
:- type compilation_unit
|
|
---> module(
|
|
module_name,
|
|
item_list
|
|
).
|
|
|
|
:- type item_list == list(item_and_context).
|
|
|
|
:- type item_and_context == pair(item, prog_context).
|
|
|
|
:- type item
|
|
---> pred_clause(prog_varset, sym_name, list(prog_term), goal)
|
|
% VarNames, PredName, HeadArgs, ClauseBody
|
|
|
|
; func_clause(prog_varset, sym_name, list(prog_term),
|
|
prog_term, goal)
|
|
% VarNames, PredName, HeadArgs, Result, ClauseBody
|
|
|
|
; type_defn(tvarset, type_defn, condition)
|
|
; inst_defn(inst_varset, inst_defn, condition)
|
|
; mode_defn(inst_varset, mode_defn, condition)
|
|
; module_defn(prog_varset, module_defn)
|
|
|
|
; pred(tvarset, inst_varset, existq_tvars, sym_name,
|
|
list(type_and_mode), maybe(determinism), condition,
|
|
purity, class_constraints)
|
|
% TypeVarNames, InstVarNames,
|
|
% ExistentiallyQuantifiedTypeVars, PredName, ArgTypes,
|
|
% Deterministicness, Cond, Purity, TypeClassContext
|
|
|
|
; func(tvarset, inst_varset, existq_tvars, sym_name,
|
|
list(type_and_mode), type_and_mode, maybe(determinism),
|
|
condition, purity, class_constraints)
|
|
% TypeVarNames, InstVarNames,
|
|
% ExistentiallyQuantifiedTypeVars, PredName, ArgTypes,
|
|
% ReturnType, Deterministicness, Cond, Purity,
|
|
% TypeClassContext
|
|
|
|
; pred_mode(inst_varset, sym_name, list(mode), maybe(determinism),
|
|
condition)
|
|
% VarNames, PredName, ArgModes, Deterministicness,
|
|
% Cond
|
|
|
|
; func_mode(inst_varset, sym_name, list(mode), mode,
|
|
maybe(determinism), condition)
|
|
% VarNames, PredName, ArgModes, ReturnValueMode,
|
|
% Deterministicness, Cond
|
|
|
|
; pragma(pragma_type)
|
|
|
|
; typeclass(list(class_constraint), class_name, list(tvar),
|
|
class_interface, tvarset)
|
|
% Constraints, ClassName, ClassParams,
|
|
% ClassMethods, VarNames
|
|
|
|
; instance(list(class_constraint), class_name, list(type),
|
|
instance_body, tvarset)
|
|
% DerivingClass, ClassName, Types,
|
|
% MethodInstances, VarNames
|
|
|
|
; nothing.
|
|
% used for items that should be ignored (currently only
|
|
% NU-Prolog `when' declarations, which are silently ignored
|
|
% for backwards compatibility).
|
|
|
|
:- type type_and_mode
|
|
---> type_only(type)
|
|
; type_and_mode(type, mode).
|
|
|
|
:- type pragma_type
|
|
---> c_header_code(string)
|
|
|
|
; c_code(string)
|
|
|
|
; c_code(pragma_c_code_attributes, sym_name, pred_or_func,
|
|
list(pragma_var), prog_varset, pragma_c_code_impl)
|
|
% Set of C code attributes, eg.:
|
|
% whether or not the C code may call Mercury,
|
|
% whether or not the C code is thread-safe
|
|
% PredName, Predicate or Function, Vars/Mode,
|
|
% VarNames, C Code Implementation Info
|
|
|
|
; type_spec(sym_name, sym_name, arity, maybe(pred_or_func),
|
|
maybe(list(mode)), type_subst, tvarset)
|
|
% PredName, SpecializedPredName, Arity,
|
|
% PredOrFunc, Modes if a specific procedure was
|
|
% specified, type substitution (using the variable
|
|
% names from the pred declaration), TVarSet
|
|
|
|
; inline(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; no_inline(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; obsolete(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; export(sym_name, pred_or_func, list(mode),
|
|
string)
|
|
% Predname, Predicate/function, Modes,
|
|
% C function name.
|
|
|
|
; import(sym_name, pred_or_func, list(mode),
|
|
pragma_c_code_attributes, string)
|
|
% Predname, Predicate/function, Modes,
|
|
% Set of C code attributes, eg.:
|
|
% whether or not the C code may call Mercury,
|
|
% whether or not the C code is thread-safe
|
|
% C function name.
|
|
|
|
; source_file(string)
|
|
% Source file name.
|
|
|
|
; unused_args(pred_or_func, sym_name, int,
|
|
proc_id, list(int))
|
|
% PredName, Arity, Mode, Optimized pred name,
|
|
% Removed arguments.
|
|
% Used for inter-module unused argument
|
|
% removal, should only appear in .opt files.
|
|
|
|
; fact_table(sym_name, arity, string)
|
|
% Predname, Arity, Fact file name.
|
|
|
|
; aditi(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; base_relation(sym_name, arity)
|
|
% Predname, Arity
|
|
%
|
|
% Eventually, these should only occur in
|
|
% automatically generated database interface
|
|
% files, but for now there's no such thing,
|
|
% so they can occur in user programs.
|
|
|
|
; aditi_index(sym_name, arity, index_spec)
|
|
% PredName, Arity, IndexType, Attributes
|
|
%
|
|
% Specify an index on a base relation.
|
|
|
|
; naive(sym_name, arity)
|
|
% Predname, Arity
|
|
% Use naive evaluation.
|
|
|
|
; psn(sym_name, arity)
|
|
% Predname, Arity
|
|
% Use predicate semi-naive evaluation.
|
|
|
|
; aditi_memo(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; aditi_no_memo(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; supp_magic(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; context(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; owner(sym_name, arity, string)
|
|
% PredName, Arity, String.
|
|
|
|
; tabled(eval_method, sym_name, int, maybe(pred_or_func),
|
|
maybe(list(mode)))
|
|
% Tabling type, Predname, Arity, PredOrFunc?, Mode?
|
|
|
|
; promise_pure(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; termination_info(pred_or_func, sym_name, list(mode),
|
|
maybe(arg_size_info), maybe(termination_info))
|
|
% the list(mode) is the declared argmodes of the
|
|
% procedure, unless there are no declared argmodes,
|
|
% in which case the inferred argmodes are used.
|
|
% This pragma is used to define information about a
|
|
% predicates termination properties. It is most
|
|
% useful where the compiler has insufficient
|
|
% information to be able to analyse the predicate.
|
|
% This includes c_code, and imported predicates.
|
|
% termination_info pragmas are used in opt and
|
|
% trans_opt files.
|
|
|
|
|
|
; terminates(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; does_not_terminate(sym_name, arity)
|
|
% Predname, Arity
|
|
|
|
; check_termination(sym_name, arity).
|
|
% Predname, Arity
|
|
|
|
% The type substitution for a `pragma type_spec' declaration.
|
|
:- type type_subst == assoc_list(tvar, type).
|
|
|
|
% This type holds information about the implementation details
|
|
% of procedures defined via `pragma c_code'.
|
|
|
|
% All the strings in this type may be accompanied by the context
|
|
% of their appearance in the source code. These contexts are
|
|
% used to tell the C compiler where the included C code comes from,
|
|
% to allow it to generate error messages that refer to the original
|
|
% appearance of the code in the Mercury program.
|
|
% The context is missing if the C code was constructed by the compiler.
|
|
:- type pragma_c_code_impl
|
|
---> ordinary( % This is a C definition of a model_det
|
|
% or model_semi procedure. (We also
|
|
% allow model_non, until everyone has
|
|
% had time to adapt to the new way
|
|
% of handling model_non pragmas.)
|
|
string, % The C code of the procedure.
|
|
maybe(prog_context)
|
|
)
|
|
; nondet( % This is a C definition of a model_non
|
|
% procedure.
|
|
string,
|
|
maybe(prog_context),
|
|
% The info saved for the time when
|
|
% backtracking reenters this procedure
|
|
% is stored in a C struct. This arg
|
|
% contains the field declarations.
|
|
|
|
string,
|
|
maybe(prog_context),
|
|
% Gives the code to be executed when
|
|
% the procedure is called for the first
|
|
% time. This code may access the input
|
|
% variables.
|
|
|
|
string,
|
|
maybe(prog_context),
|
|
% Gives the code to be executed when
|
|
% control backtracks into the procedure.
|
|
% This code may not access the input
|
|
% variables.
|
|
|
|
pragma_shared_code_treatment,
|
|
% How should the shared code be
|
|
% treated during code generation.
|
|
string,
|
|
maybe(prog_context)
|
|
% Shared code that is executed after
|
|
% both the previous code fragments.
|
|
% May not access the input variables.
|
|
).
|
|
|
|
% The use of this type is explained in the comment at the top of
|
|
% pragma_c_gen.m.
|
|
:- type pragma_shared_code_treatment
|
|
---> duplicate
|
|
; share
|
|
; automatic.
|
|
|
|
% 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.
|
|
% Any code that creates new class constraints must
|
|
% ensure that this invariant is preserved,
|
|
% probably by using strip_term_contexts/2 in type_util.m.
|
|
:- type class_constraint
|
|
---> constraint(class_name, list(type)).
|
|
|
|
:- type class_constraints
|
|
---> constraints(
|
|
list(class_constraint), % ordinary (universally quantified)
|
|
list(class_constraint) % existentially quantified constraints
|
|
).
|
|
|
|
:- type class_name == sym_name.
|
|
|
|
:- type class_interface == list(class_method).
|
|
|
|
:- type class_method
|
|
---> pred(tvarset, inst_varset, existq_tvars, sym_name,
|
|
list(type_and_mode), maybe(determinism), condition,
|
|
class_constraints, prog_context)
|
|
% TypeVarNames, InstVarNames,
|
|
% ExistentiallyQuantifiedTypeVars,
|
|
% PredName, ArgTypes, Determinism, Cond
|
|
% ClassContext, Context
|
|
|
|
; func(tvarset, inst_varset, existq_tvars, sym_name,
|
|
list(type_and_mode), type_and_mode,
|
|
maybe(determinism), condition,
|
|
class_constraints, prog_context)
|
|
% TypeVarNames, InstVarNames,
|
|
% ExistentiallyQuantfiedTypeVars,
|
|
% PredName, ArgTypes, ReturnType,
|
|
% Determinism, Cond
|
|
% ClassContext, Context
|
|
|
|
; pred_mode(inst_varset, sym_name, list(mode),
|
|
maybe(determinism), condition,
|
|
prog_context)
|
|
% InstVarNames, PredName, ArgModes,
|
|
% Determinism, Cond
|
|
% Context
|
|
|
|
; func_mode(inst_varset, sym_name, list(mode), mode,
|
|
maybe(determinism), condition,
|
|
prog_context)
|
|
% InstVarNames, PredName, ArgModes,
|
|
% ReturnValueMode,
|
|
% Determinism, Cond
|
|
% Context
|
|
.
|
|
|
|
:- type instance_method
|
|
---> func_instance(sym_name, sym_name, arity, prog_context)
|
|
% Method, Instance, Arity,
|
|
% Line number of declaration
|
|
; pred_instance(sym_name, sym_name, arity, prog_context)
|
|
% Method, Instance, Arity,
|
|
% Line number of declaration
|
|
.
|
|
|
|
:- type instance_body
|
|
---> abstract
|
|
; concrete(instance_methods).
|
|
|
|
:- type instance_methods == list(instance_method).
|
|
|
|
% an abstract type for representing a set of
|
|
% `pragma_c_code_attribute's.
|
|
:- type pragma_c_code_attributes.
|
|
|
|
:- pred default_attributes(pragma_c_code_attributes).
|
|
:- mode default_attributes(out) is det.
|
|
|
|
:- pred may_call_mercury(pragma_c_code_attributes, may_call_mercury).
|
|
:- mode may_call_mercury(in, out) is det.
|
|
|
|
:- pred set_may_call_mercury(pragma_c_code_attributes, may_call_mercury,
|
|
pragma_c_code_attributes).
|
|
:- mode set_may_call_mercury(in, in, out) is det.
|
|
|
|
:- pred thread_safe(pragma_c_code_attributes, thread_safe).
|
|
:- mode thread_safe(in, out) is det.
|
|
|
|
:- pred set_thread_safe(pragma_c_code_attributes, thread_safe,
|
|
pragma_c_code_attributes).
|
|
:- mode set_thread_safe(in, in, out) is det.
|
|
|
|
% For pragma c_code, there are two different calling conventions,
|
|
% one for C code that may recursively call Mercury code, and another
|
|
% more efficient one for the case when we know that the C code will
|
|
% not recursively invoke Mercury code.
|
|
:- type may_call_mercury
|
|
---> may_call_mercury
|
|
; will_not_call_mercury.
|
|
|
|
% If thread_safe execution is enabled, then we need to put a mutex
|
|
% around the C code for each `pragma c_code' declaration, unless
|
|
% it's declared to be thread_safe.
|
|
:- type thread_safe
|
|
---> not_thread_safe
|
|
; thread_safe.
|
|
|
|
:- type pragma_var
|
|
---> pragma_var(prog_var, string, mode).
|
|
% variable, name, mode
|
|
% we explicitly store the name because we need the real
|
|
% name in code_gen
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Here's how clauses and goals are represented.
|
|
% a => b --> implies(a, b)
|
|
% a <= b --> implies(b, a) [just flips the goals around!]
|
|
% a <=> b --> equivalent(a, b)
|
|
|
|
% clause/4 defined above
|
|
|
|
:- type goal == pair(goal_expr, prog_context).
|
|
|
|
:- type goal_expr
|
|
% conjunctions
|
|
---> (goal , goal) % (non-empty) conjunction
|
|
; true % empty conjunction
|
|
; {goal & goal} % parallel conjunction
|
|
% (The curly braces just quote the '&'/2.)
|
|
|
|
% disjunctions
|
|
; {goal ; goal} % (non-empty) disjunction
|
|
% (The curly braces just quote the ';'/2.)
|
|
; fail % empty disjunction
|
|
|
|
% quantifiers
|
|
; { some(prog_vars, goal) }
|
|
% existential quantification
|
|
% (The curly braces just quote the 'some'/2.)
|
|
; all(prog_vars, goal) % universal quantification
|
|
|
|
% implications
|
|
; implies(goal, goal) % A => B
|
|
; equivalent(goal, goal) % A <=> B
|
|
|
|
% negation and if-then-else
|
|
; not(goal)
|
|
; if_then(prog_vars, goal, goal)
|
|
; if_then_else(prog_vars, goal, goal, goal)
|
|
|
|
% atomic goals
|
|
; call(sym_name, list(prog_term), purity)
|
|
; unify(prog_term, prog_term).
|
|
|
|
|
|
% These type equivalences are for the type 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_term == term(prog_var_type).
|
|
:- type prog_vars == list(prog_var).
|
|
|
|
% A prog_context is just a term__context.
|
|
|
|
:- type prog_context == term__context.
|
|
|
|
:- type goals == list(goal).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This is how types are represented.
|
|
|
|
% one day we might allow types to take
|
|
% value parameters as well as type parameters.
|
|
|
|
% type_defn/3 define above
|
|
|
|
:- type type_defn
|
|
---> du_type(sym_name, list(type_param), list(constructor),
|
|
maybe(equality_pred)
|
|
)
|
|
; uu_type(sym_name, list(type_param), list(type))
|
|
; eqv_type(sym_name, list(type_param), type)
|
|
; abstract_type(sym_name, list(type_param)).
|
|
|
|
:- type constructor
|
|
---> ctor(
|
|
existq_tvars,
|
|
list(class_constraint), % existential constraints
|
|
sym_name,
|
|
list(constructor_arg)
|
|
).
|
|
|
|
:- type constructor_arg == pair(string, type).
|
|
|
|
% 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.
|
|
|
|
% probably type parameters should be variables not terms.
|
|
:- type type_param == term(tvar_type).
|
|
|
|
% Module qualified types are represented as ':'/2 terms.
|
|
% Use type_util:type_to_type_id to convert a type to a qualified
|
|
% type_id and a list of arguments.
|
|
% type_util:construct_type to construct a type from a type_id
|
|
% and a list of arguments.
|
|
:- type (type) == term(tvar_type).
|
|
:- type type_term == term(tvar_type).
|
|
|
|
:- type tvar_type ---> type_var.
|
|
:- type tvar == var(tvar_type).
|
|
% used for type variables
|
|
:- type tvarset == varset(tvar_type).
|
|
% used for sets of type variables
|
|
:- type tsubst == map(tvar, type). % used for type substitutions
|
|
|
|
% existq_tvars is used to record the set of type variables which are
|
|
% existentially quantified
|
|
:- type existq_tvars == list(tvar).
|
|
|
|
% Types may have arbitrary assertions associated with them
|
|
% (eg. you can define a type which represents sorted lists).
|
|
% Similarly, pred declarations can have assertions attached.
|
|
% The compiler will ignore these assertions - they are intended
|
|
% to be used by other tools, such as the debugger.
|
|
|
|
:- type condition
|
|
---> true
|
|
; where(term).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This is how instantiatednesses and modes are represented.
|
|
% Note that while we use the normal term data structure to represent
|
|
% type terms (see above), we need a separate data structure for inst
|
|
% terms.
|
|
|
|
:- 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).
|
|
|
|
% inst_defn/3 defined above
|
|
|
|
:- type inst_defn
|
|
---> eqv_inst(sym_name, list(inst_param), inst)
|
|
; abstract_inst(sym_name, list(inst_param)).
|
|
|
|
% probably inst parameters should be variables not terms
|
|
:- type inst_param == inst_term.
|
|
|
|
% 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 it's 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(inst))
|
|
; merge_inst(inst, inst)
|
|
; unify_inst(is_live, inst, inst, unify_is_real)
|
|
; ground_inst(inst_name, is_live, uniqueness, unify_is_real)
|
|
; any_inst(inst_name, is_live, uniqueness, unify_is_real)
|
|
; shared_inst(inst_name)
|
|
; mostly_uniq_inst(inst_name)
|
|
; typed_ground(uniqueness, type)
|
|
; typed_inst(type, inst_name).
|
|
|
|
% 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 ---> live ; 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.
|
|
|
|
% mode_defn/3 defined above
|
|
|
|
:- type mode_defn
|
|
---> eqv_mode(sym_name, list(inst_param), mode).
|
|
|
|
:- type (mode)
|
|
---> ((inst) -> (inst))
|
|
; user_defined_mode(sym_name, list(inst)).
|
|
|
|
% mode/4 defined above
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This is how module-system declarations (such as imports
|
|
% and exports) are represented.
|
|
|
|
:- type module_defn
|
|
---> module(module_name)
|
|
; end_module(module_name)
|
|
|
|
; interface
|
|
; implementation
|
|
|
|
; private_interface
|
|
% This is used internally by the compiler,
|
|
% to identify items which originally
|
|
% came from an implementation section
|
|
% for a module that contains sub-modules;
|
|
% such items need to be exported to the
|
|
% sub-modules.
|
|
|
|
; imported
|
|
% This is used internally by the compiler,
|
|
% to identify declarations which originally
|
|
% came from some other module imported with
|
|
% a `:- import_module' declaration.
|
|
; used
|
|
% This is used internally by the compiler,
|
|
% to identify declarations which originally
|
|
% came from some other module and for which
|
|
% all uses must be module qualified. This
|
|
% applies to items from modules imported using
|
|
% `:- use_module', and items from `.opt'
|
|
% and `.int2' files.
|
|
; opt_imported
|
|
% This is used internally by the compiler,
|
|
% to identify items which originally
|
|
% came from a .opt file.
|
|
|
|
; external(sym_name_specifier)
|
|
|
|
; export(sym_list)
|
|
; import(sym_list)
|
|
; use(sym_list)
|
|
|
|
; include_module(list(module_name)).
|
|
|
|
:- type sym_list
|
|
---> sym(list(sym_specifier))
|
|
; pred(list(pred_specifier))
|
|
; func(list(func_specifier))
|
|
; cons(list(cons_specifier))
|
|
; op(list(op_specifier))
|
|
; adt(list(adt_specifier))
|
|
; type(list(type_specifier))
|
|
; module(list(module_specifier)).
|
|
|
|
:- type sym_specifier
|
|
---> sym(sym_name_specifier)
|
|
; typed_sym(typed_cons_specifier)
|
|
; pred(pred_specifier)
|
|
; func(func_specifier)
|
|
; cons(cons_specifier)
|
|
; op(op_specifier)
|
|
; adt(adt_specifier)
|
|
; type(type_specifier)
|
|
; module(module_specifier).
|
|
:- type pred_specifier
|
|
---> sym(sym_name_specifier)
|
|
; name_args(sym_name, list(type)).
|
|
:- type func_specifier == cons_specifier.
|
|
:- type cons_specifier
|
|
---> sym(sym_name_specifier)
|
|
; typed(typed_cons_specifier).
|
|
:- type typed_cons_specifier
|
|
---> name_args(sym_name, list(type))
|
|
; name_res(sym_name_specifier, type)
|
|
; name_args_res(sym_name, list(type), type).
|
|
:- type adt_specifier == sym_name_specifier.
|
|
:- type type_specifier == sym_name_specifier.
|
|
:- type op_specifier
|
|
---> sym(sym_name_specifier)
|
|
% operator fixity specifiers not yet implemented
|
|
; fixity(sym_name_specifier, fixity).
|
|
:- type fixity
|
|
---> infix
|
|
; prefix
|
|
; postfix
|
|
; binary_prefix
|
|
; binary_postfix.
|
|
:- type sym_name_specifier
|
|
---> name(sym_name)
|
|
; name_arity(sym_name, arity).
|
|
:- type sym_name
|
|
---> unqualified(string)
|
|
; qualified(module_specifier, string).
|
|
|
|
:- type module_specifier == sym_name.
|
|
:- type module_name == sym_name.
|
|
:- type arity == int.
|
|
|
|
% Describes whether an item can be used without an
|
|
% explicit module qualifier.
|
|
:- type need_qualifier
|
|
---> must_be_qualified
|
|
; may_be_unqualified.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- type pragma_c_code_attributes
|
|
---> attributes(
|
|
may_call_mercury,
|
|
thread_safe
|
|
).
|
|
|
|
default_attributes(attributes(may_call_mercury, not_thread_safe)).
|
|
|
|
may_call_mercury(Attrs, MayCallMercury) :-
|
|
Attrs = attributes(MayCallMercury, _).
|
|
|
|
thread_safe(Attrs, ThreadSafe) :-
|
|
Attrs = attributes(_, ThreadSafe).
|
|
|
|
set_may_call_mercury(Attrs0, MayCallMercury, Attrs) :-
|
|
Attrs0 = attributes(_, ThreadSafe),
|
|
Attrs = attributes(MayCallMercury, ThreadSafe).
|
|
|
|
set_thread_safe(Attrs0, ThreadSafe, Attrs) :-
|
|
Attrs0 = attributes(MayCallMercury, _),
|
|
Attrs = attributes(MayCallMercury, ThreadSafe).
|