Files
mercury/compiler/type_util.m
Fergus Henderson 11d8161692 Add support for nested modules.
Estimated hours taken: 50

Add support for nested modules.

- module names may themselves be module-qualified
- modules may contain `:- include_module' declarations
  which name sub-modules
- a sub-module has access to all the declarations in the
  parent module (including its implementation section).

This support is not yet complete; see the BUGS and LIMITATIONS below.

LIMITATIONS
- source file names must match module names
	(just as they did previously)
- mmc doesn't allow path names on the command line any more
	(e.g. `mmc --make-int ../library/foo.m').
- import_module declarations must use the fully-qualified module name
- module qualifiers must use the fully-qualified module name
- no support for root-qualified module names
	(e.g. `:parent:child' instead of `parent:child').
- modules may not be physically nested (only logical nesting, via
  `include_module').

BUGS
- doesn't check that the parent module is imported/used before allowing
	import/use of its sub-modules.
- doesn't check that there is an include_module declaration in the
	parent for each module claiming to be a child of that parent
- privacy of private modules is not enforced

-------------------

NEWS:
	Mention that we support nested modules.

library/ops.m:
library/nc_builtin.nl:
library/sp_builtin.nl:
compiler/mercury_to_mercury.m:
	Add `include_module' as a new prefix operator.
	Change the associativity of `:' from xfy to yfx
	(since this made parsing module qualifiers slightly easier).

compiler/prog_data.m:
	Add new `include_module' declaration.
	Change the `module_name' and `module_specifier' types
	from strings to sym_names, so that module names can
	themselves be module qualified.

compiler/modules.m:
	Add predicates module_name_to_file_name/2 and
	file_name_to_module_name/2.
	Lots of changes to handle parent module dependencies,
	to create parent interface (`.int0') files, to read them in,
	to output correct dependencies information for them to the
	`.d' and `.dep' files, etc.
	Rewrite a lot of the code to improve the readability
	(add comments, use subroutines, better variable names).
	Also fix a couple of bugs:
	- generate_dependencies was using the transitive implementation
	  dependencies rather than the transitive interface dependencies
	  to compute the `.int3' dependencies when writing `.d' files
	  (this bug was introduced during crs's changes to support
	  `.trans_opt' files)
	- when creating the `.int' file, it was reading in the
	  interfaces for modules imported in the implementation section,
	  not just those in the interface section.
	  This meant that the compiler missed a lot of errors.

library/graph.m:
library/lexer.m:
library/term.m:
library/term_io.m:
library/varset.m:
compiler/*.m:
	Add `:- import_module' declarations to the interface needed
	by declarations in the interface.  (The previous version
	of the compiler did not detect these missing interface imports,
	due to the above-mentioned bug in modules.m.)

compiler/mercury_compile.m:
compiler/intermod.m:
	Change mercury_compile__maybe_grab_optfiles and
	intermod__grab_optfiles so that they grab the opt files for
	parent modules as well as the ones for imported modules.

compiler/mercury_compile.m:
	Minor changes to handle parent module dependencies.
	(Also improve the wording of the warning about trans-opt
	dependencies.)

compiler/make_hlds.m:
compiler/module_qual.m:
	Ignore `:- include_module' declarations.

compiler/module_qual.m:
	A couple of small changes to handle nested module names.

compiler/prog_out.m:
compiler/prog_util.m:
	Add new predicates string_to_sym_name/3 (prog_util.m) and
	sym_name_to_string/{2,3} (prog_out.m).

compiler/*.m:
	Replace many occurrences of `string' with `module_name'.
	Change code that prints out module names or converts
	them to strings or filenames to handle the fact that
	module names are now sym_names intead of strings.
	Also change a few places (e.g. in intermod.m, hlds_module.m)
	where the code assumed that any qualified symbol was
	fully-qualified.

compiler/prog_io.m:
compiler/prog_io_goal.m:
	Move sym_name_and_args/3, parse_qualified_term/4 and
	parse_qualified_term/5 preds from prog_io_goal.m to prog_io.m,
	since they are very similar to the parse_symbol_name/2 predicate
	already in prog_io.m.  Rewrite these predicates, both
	to improve maintainability, and to handle the newly
	allowed syntax (module-qualified module names).
	Rename parse_qualified_term/5 as `parse_implicit_qualified_term'.

compiler/prog_io.m:
	Rewrite the handling of `:- module' and `:- end_module'
	declarations, so that it can handle nested modules.
	Add code to parse `include_module' declarations.

compiler/prog_util.m:
compiler/*.m:
	Add new predicates mercury_public_builtin_module/1 and
	mercury_private_builtin_module/1 in prog_util.m.
	Change most of the hard-coded occurrences of "mercury_builtin"
	to call mercury_private_builtin_module/1 or
	mercury_public_builtin_module/1 or both.

compiler/llds_out.m:
	Add llds_out__sym_name_mangle/2, for mangling module names.

compiler/special_pred.m:
compiler/mode_util.m:
compiler/clause_to_proc.m:
compiler/prog_io_goal.m:
compiler/lambda.m:
compiler/polymorphism.m:
	Move the predicates in_mode/1, out_mode/1, and uo_mode/1
	from special_pred.m to mode_util.m, and change various
	hard-coded definitions to instead call these predicates.

compiler/polymorphism.m:
	Ensure that the type names `type_info' and `typeclass_info' are
	module-qualified in the generated code.  This avoids a problem
	where the code generated by polymorphism.m was not considered
	type-correct, due to the type `type_info' not matching
	`mercury_builtin:type_info'.

compiler/check_typeclass.m:
	Simplify the code for check_instance_pred and
	get_matching_instance_pred_ids.

compiler/mercury_compile.m:
compiler/modules.m:
	Disallow directory names in command-line arguments.

compiler/options.m:
compiler/handle_options.m:
compiler/mercury_compile.m:
compiler/modules.m:
	Add a `--make-private-interface' option.
	The private interface file `<module>.int0' contains
	all the declarations in the module; it is used for
	compiling sub-modules.

scripts/Mmake.rules:
scripts/Mmake.vars.in:
	Add support for creating `.int0' and `.date0' files
	by invoking mmc with `--make-private-interface'.

doc/user_guide.texi:
	Document `--make-private-interface' and the `.int0'
	and `.date0' file extensions.

doc/reference_manual.texi:
	Document nested modules.

util/mdemangle.c:
profiler/demangle.m:
	Demangle names with multiple module qualifiers.

tests/general/Mmakefile:
tests/general/string_format_test.m:
tests/general/string_format_test.exp:
tests/general/string__format_test.m:
tests/general/string__format_test.exp:
tests/general/.cvsignore:
	Change the `:- module string__format_test' declaration in
	`string__format_test.m' to `:- module string_format_test',
	because with the original declaration the `__' was taken
	as a module qualifier, which lead to an error message.
	Hence rename the file accordingly, to avoid the warning
	about file name not matching module name.

tests/invalid/Mmakefile:
tests/invalid/missing_interface_import.m:
tests/invalid/missing_interface_import.err_exp:
	Regression test to check that the compiler reports
	errors for missing `import_module' in the interface section.

tests/invalid/*.err_exp:
tests/warnings/unused_args_test.exp:
tests/warnings/unused_import.exp:
	Update the expected diagnostics output for the test cases to
	reflect a few minor changes to the warning messages.

tests/hard_coded/Mmakefile:
tests/hard_coded/parent.m:
tests/hard_coded/parent.child.m:
tests/hard_coded/parent.exp:
tests/hard_coded/parent2.m:
tests/hard_coded/parent2.child.m:
tests/hard_coded/parent2.exp:
	Two simple tests case for the use of nested modules with
	separate compilation.
1998-03-03 17:48:14 +00:00

736 lines
24 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1994-1998 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: type_util.m.
% Main author: fjh.
% This file provides some utility predicates which operate on types.
% It is used by various stages of the compilation after type-checking,
% include the mode checker and the code generator.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module type_util.
:- interface.
:- import_module hlds_module, hlds_pred, hlds_data, prog_data.
:- import_module list, term, map.
%-----------------------------------------------------------------------------%
% Succeed iff type is an "atomic" type - one which can be
% unified using a simple_test rather than a complicated_unify.
:- pred type_is_atomic(type, module_info).
:- mode type_is_atomic(in, in) is semidet.
% type_is_higher_order(Type, PredOrFunc, ArgTypes) succeeds iff
% Type is a higher-order predicate or function type with the specified
% argument types (for functions, the return type is appended to the
% end of the argument types).
:- pred type_is_higher_order(type, pred_or_func, list(type)).
:- mode type_is_higher_order(in, out, out) is semidet.
% type_id_is_higher_order(TypeId, PredOrFunc) succeeds iff
% TypeId is a higher-order predicate or function type.
:- pred type_id_is_higher_order(type_id, pred_or_func).
:- mode type_id_is_higher_order(in, out) is semidet.
% Given a type, determine what sort of type it is.
:- pred classify_type(type, module_info, builtin_type).
:- mode classify_type(in, in, out) is det.
:- type builtin_type ---> int_type
; char_type
; str_type
; float_type
; pred_type
; enum_type
; polymorphic_type
; user_type.
% Given a non-variable type, return its type-id and argument types.
:- pred type_to_type_id(type, type_id, list(type)).
:- mode type_to_type_id(in, out, out) is semidet.
% Given a variable type, return its type variable.
:- pred type_util__var(type, var).
:- mode type_util__var(in, out) is semidet.
:- mode type_util__var(out, in) is det.
% Given a type_id, a list of argument types and maybe a context,
% construct a type.
:- pred construct_type(type_id, list(type), (type)).
:- mode construct_type(in, in, out) is det.
:- pred construct_type(type_id, list(type), term__context, (type)).
:- mode construct_type(in, in, in, out) is det.
% Given a constant and an arity, return a type_id.
% Fails if the constant is not an atom.
:- pred make_type_id(const, int, type_id).
:- mode make_type_id(in, in, out) is semidet.
% Given a type_id, look up its module/name/arity
:- pred type_util__type_id_module(module_info, type_id, module_name).
:- mode type_util__type_id_module(in, in, out) is det.
:- pred type_util__type_id_name(module_info, type_id, string).
:- mode type_util__type_id_name(in, in, out) is det.
:- pred type_util__type_id_arity(module_info, type_id, arity).
:- mode type_util__type_id_arity(in, in, out) is det.
% If the type is a du type, return the list of its constructors.
:- pred type_constructors(type, module_info, list(constructor)).
:- mode type_constructors(in, in, out) is semidet.
% Work out the types of the arguments of a functor.
:- pred type_util__get_cons_id_arg_types(module_info::in, (type)::in,
cons_id::in, list(type)::out) is det.
% Given a list of constructors for a type,
% check whether that type is a no_tag type
% (i.e. one with only one constructor, and
% whose one constructor has only one argument,
% and which is not mercury_builtin:type_info/1),
% and if so, return its constructor symbol and argument type.
:- pred type_is_no_tag_type(list(constructor), sym_name, type).
:- mode type_is_no_tag_type(in, out, out) is semidet.
% Unify (with occurs check) two types with respect to a type
% substitution and update the type bindings.
% The third argument is a list of type variables which cannot
% be bound (i.e. head type variables).
:- pred type_unify(type, type, list(tvar), tsubst, tsubst).
:- mode type_unify(in, in, in, in, out) is semidet.
:- pred type_unify_list(list(type), list(type), list(tvar), tsubst, tsubst).
:- mode type_unify_list(in, in, in, in, out) is semidet.
% Return a list of the type variables of a type.
:- pred type_util__vars(type, list(tvar)).
:- mode type_util__vars(in, out) is det.
% type_list_subsumes(TypesA, TypesB, Subst) succeeds iff the list
% TypesA subsumes (is more general than) TypesB, producing a
% type substitution which when applied to TypesA will give TypesB.
:- pred type_list_subsumes(list(type), list(type), tsubst).
:- mode type_list_subsumes(in, in, out) is semidet.
% type_list_matches_exactly(TypesA, TypesB) succeeds iff TypesA and
% TypesB are exactly the same modulo variable renaming.
:- pred type_list_matches_exactly(list(type), list(type)).
:- mode type_list_matches_exactly(in, in) is semidet.
% apply a type substitution (i.e. map from tvar -> type)
% to all the types in a variable typing (i.e. map from var -> type).
:- pred apply_substitution_to_type_map(map(var, type), tsubst, map(var, type)).
:- mode apply_substitution_to_type_map(in, in, out) is det.
% same thing as above, except for a recursive substitution
% (i.e. we keep applying the substitution recursively until
% there are no more changes).
:- pred apply_rec_substitution_to_type_map(map(var, type), tsubst,
map(var, type)).
:- mode apply_rec_substitution_to_type_map(in, in, out) is det.
% Update a map from tvar to type_info_locn, using the type substititon
% to rename tvars and a variable substition to rename vars.
%
% If tvar maps to a another type variable, we keep the new
% variable, if it maps to a type, we remove it from the map.
:- pred apply_substitutions_to_var_map(map(tvar, type_info_locn), tsubst,
map(var, var), map(tvar, type_info_locn)).
:- mode apply_substitutions_to_var_map(in, in, in, out) is det.
:- pred apply_rec_subst_to_constraints(substitution, list(class_constraint),
list(class_constraint)).
:- mode apply_rec_subst_to_constraints(in, in, out) is det.
:- pred apply_rec_subst_to_constraint(substitution, class_constraint,
class_constraint).
:- mode apply_rec_subst_to_constraint(in, in, out) is det.
:- pred apply_subst_to_constraints(substitution, list(class_constraint),
list(class_constraint)).
:- mode apply_subst_to_constraints(in, in, out) is det.
:- pred apply_subst_to_constraint(substitution, class_constraint,
class_constraint).
:- mode apply_subst_to_constraint(in, in, out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module bool, require, std_util.
:- import_module prog_io, prog_io_goal, prog_util.
type_util__type_id_module(_ModuleInfo, TypeName - _Arity, ModuleName) :-
sym_name_get_module_name(TypeName, unqualified(""), ModuleName).
type_util__type_id_name(_ModuleInfo, Name0 - _Arity, Name) :-
unqualify_name(Name0, Name).
type_util__type_id_arity(_ModuleInfo, _Name - Arity, Arity).
type_is_atomic(Type, ModuleInfo) :-
classify_type(Type, ModuleInfo, BuiltinType),
BuiltinType \= polymorphic_type,
BuiltinType \= pred_type,
BuiltinType \= user_type.
type_util__var(term__variable(Var), Var).
%-----------------------------------------------------------------------------%
% Given a type, determine what sort of type it is.
classify_type(VarType, ModuleInfo, Type) :-
(
VarType = term__variable(_)
->
Type = polymorphic_type
;
VarType = term__functor(term__atom("character"), [], _)
->
Type = char_type
;
VarType = term__functor(term__atom("int"), [], _)
->
Type = int_type
;
VarType = term__functor(term__atom("float"), [], _)
->
Type = float_type
;
VarType = term__functor(term__atom("string"), [], _)
->
Type = str_type
;
type_is_higher_order(VarType, _, _)
->
Type = pred_type
;
type_is_enumeration(VarType, ModuleInfo)
->
Type = enum_type
;
Type = user_type
).
type_is_higher_order(Type, PredOrFunc, PredArgTypes) :-
(
Type = term__functor(term__atom("pred"),
PredArgTypes, _),
PredOrFunc = predicate
;
Type = term__functor(term__atom("="),
[term__functor(term__atom("func"),
FuncArgTypes, _),
FuncRetType], _),
list__append(FuncArgTypes, [FuncRetType], PredArgTypes),
PredOrFunc = function
).
type_id_is_higher_order(SymName - Arity, PredOrFunc) :-
unqualify_name(SymName, TypeName),
(
TypeName = "pred",
PredOrFunc = predicate
;
TypeName = "=",
Arity = 2,
PredOrFunc = function
).
:- pred type_is_enumeration(type, module_info).
:- mode type_is_enumeration(in, in) is semidet.
type_is_enumeration(Type, ModuleInfo) :-
type_to_type_id(Type, TypeId, _),
module_info_types(ModuleInfo, TypeDefnTable),
map__search(TypeDefnTable, TypeId, TypeDefn),
hlds_data__get_type_defn_body(TypeDefn, TypeBody),
TypeBody = du_type(_, _, IsEnum, _),
IsEnum = yes.
type_to_type_id(Type, SymName - Arity, Args) :-
sym_name_and_args(Type, SymName, Args1),
% higher order types may have representations where
% their arguments don't directly correspond to the
% arguments of the term.
(
type_is_higher_order(Type, _, PredArgTypes)
->
Args = PredArgTypes,
list__length(Args1, Arity) % functions have arity 2,
% (they are =/2)
;
Args = Args1,
list__length(Args, Arity)
).
construct_type(TypeId, Args, Type) :-
term__context_init(Context),
construct_type(TypeId, Args, Context, Type).
construct_type(TypeId, Args, Context, Type) :-
(
type_id_is_higher_order(TypeId, PredOrFunc)
->
(
PredOrFunc = predicate,
NewArgs = Args
;
PredOrFunc = function,
pred_args_to_func_args(Args, FuncArgTypes, FuncRetType),
NewArgs = [term__functor(term__atom("func"),
FuncArgTypes, Context),
FuncRetType]
)
;
NewArgs = Args
),
TypeId = SymName - _,
construct_qualified_term(SymName, NewArgs, Context, Type).
%-----------------------------------------------------------------------------%
% Given a constant and an arity, return a type_id.
% This really ought to take a name and an arity -
% use of integers/floats/strings as type names should
% be rejected by the parser in prog_io.m, not in module_qual.m.
make_type_id(term__atom(Name), Arity, unqualified(Name) - Arity).
%-----------------------------------------------------------------------------%
% If the type is a du type, return the list of its constructors.
type_constructors(Type, ModuleInfo, Constructors) :-
type_to_type_id(Type, TypeId, TypeArgs),
module_info_types(ModuleInfo, TypeTable),
map__search(TypeTable, TypeId, TypeDefn),
hlds_data__get_type_defn_tparams(TypeDefn, TypeParams),
hlds_data__get_type_defn_body(TypeDefn, TypeBody),
TypeBody = du_type(Constructors0, _, _, _),
substitute_type_args(TypeParams, TypeArgs, Constructors0,
Constructors).
%-----------------------------------------------------------------------------%
type_util__get_cons_id_arg_types(ModuleInfo, VarType, ConsId, ArgTypes) :-
(
type_to_type_id(VarType, TypeId, TypeArgs),
module_info_ctors(ModuleInfo, Ctors),
% will fail for builtin cons_ids.
map__search(Ctors, ConsId, ConsDefns),
CorrectCons = lambda([ConsDefn::in] is semidet, (
ConsDefn = hlds_cons_defn(_, TypeId, _)
)),
list__filter(CorrectCons, ConsDefns,
[hlds_cons_defn(ArgTypes0, _, _)]),
ArgTypes0 \= []
->
module_info_types(ModuleInfo, Types),
map__lookup(Types, TypeId, TypeDefn),
hlds_data__get_type_defn_tparams(TypeDefn, TypeDefnParams),
term__term_list_to_var_list(TypeDefnParams, TypeDefnVars),
term__substitute_corresponding_list(TypeDefnVars, TypeArgs,
ArgTypes0, ArgTypes)
;
ArgTypes = []
).
%-----------------------------------------------------------------------------%
% The checks for type_info and base_type_info
% are needed because those types lie about their
% arity; it might be cleaner to change that in
% mercury_builtin.m, but that would cause some
% bootstrapping difficulties.
% It might be slightly better to check for mercury_builtin:type_info
% etc. rather than just checking the unqualified type name,
% but I found it difficult to verify that the constructors
% would always be fully module-qualified at points where
% type_is_no_tag_type/3 is called.
type_is_no_tag_type(Ctors, Ctor, Type) :-
Ctors = [Ctor - [_FieldName - Type]],
unqualify_name(Ctor, Name),
Name \= "type_info",
Name \= "base_type_info",
Name \= "typeclass_info",
Name \= "base_typeclass_info".
%-----------------------------------------------------------------------------%
% Substitute the actual values of the type parameters
% in list of constructors, for a particular instance of
% a polymorphic type.
:- pred substitute_type_args(list(type_param), list(type),
list(constructor), list(constructor)).
:- mode substitute_type_args(in, in, in, out) is det.
substitute_type_args(TypeParams0, TypeArgs, Constructors0, Constructors) :-
( TypeParams0 = [] ->
Constructors = Constructors0
;
term__term_list_to_var_list(TypeParams0, TypeParams),
map__from_corresponding_lists(TypeParams, TypeArgs, Subst),
substitute_type_args_2(Constructors0, Subst, Constructors)
).
:- pred substitute_type_args_2(list(constructor), substitution,
list(constructor)).
:- mode substitute_type_args_2(in, in, out) is det.
substitute_type_args_2([], _, []).
substitute_type_args_2([Name - Args0 | Ctors0], Subst,
[Name - Args | Ctors]) :-
substitute_type_args_3(Args0, Subst, Args),
substitute_type_args_2(Ctors0, Subst, Ctors).
:- pred substitute_type_args_3(list(constructor_arg), substitution,
list(constructor_arg)).
:- mode substitute_type_args_3(in, in, out) is det.
substitute_type_args_3([], _, []).
substitute_type_args_3([Name - Arg0 | Args0], Subst, [Name - Arg | Args]) :-
term__apply_substitution(Arg0, Subst, Arg),
substitute_type_args_3(Args0, Subst, Args).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% Check whether TypesA subsumes TypesB, and if so return
% a type substitution that will map from TypesA to TypesB.
type_list_subsumes(TypesA, TypesB, TypeSubst) :-
%
% TypesA subsumes TypesB iff TypesA can be unified with TypesB
% without binding any of the type variables in TypesB.
%
term__vars_list(TypesB, TypesBVars),
map__init(TypeSubst0),
type_unify_list(TypesA, TypesB, TypesBVars, TypeSubst0, TypeSubst).
%-----------------------------------------------------------------------------%
% If this becomes a performance bottleneck, it can probably be coded
% more efficiently.
type_list_matches_exactly(TypesA, TypesB) :-
type_list_subsumes(TypesA, TypesB, _),
type_list_subsumes(TypesB, TypesA, _).
%-----------------------------------------------------------------------------%
% Types are represented as terms, but we can't just use term__unify
% because we need to avoid binding any of the "head type params"
% (the type variables that occur in the head of the clause),
% and because one day we might want to handle equivalent types.
type_unify(term__variable(X), term__variable(Y), HeadTypeParams, Bindings0,
Bindings) :-
( list__member(Y, HeadTypeParams) ->
type_unify_head_type_param(X, Y, HeadTypeParams,
Bindings0, Bindings)
; list__member(X, HeadTypeParams) ->
type_unify_head_type_param(Y, X, HeadTypeParams,
Bindings0, Bindings)
; map__search(Bindings0, X, BindingOfX) ->
( map__search(Bindings0, Y, BindingOfY) ->
% both X and Y already have bindings - just
% unify the types they are bound to
type_unify(BindingOfX, BindingOfY, HeadTypeParams,
Bindings0, Bindings)
;
term__apply_rec_substitution(BindingOfX,
Bindings0, SubstBindingOfX),
% Y is a type variable which hasn't been bound yet
( SubstBindingOfX = term__variable(Y) ->
Bindings = Bindings0
;
\+ term__occurs(SubstBindingOfX, Y, Bindings0),
map__det_insert(Bindings0, Y, SubstBindingOfX,
Bindings)
)
)
;
( map__search(Bindings0, Y, BindingOfY) ->
term__apply_rec_substitution(BindingOfY,
Bindings0, SubstBindingOfY),
% X is a type variable which hasn't been bound yet
( SubstBindingOfY = term__variable(X) ->
Bindings = Bindings0
;
\+ term__occurs(SubstBindingOfY, X, Bindings0),
map__det_insert(Bindings0, X, SubstBindingOfY,
Bindings)
)
;
% both X and Y are unbound type variables -
% bind one to the other
( X = Y ->
Bindings = Bindings0
;
map__det_insert(Bindings0, X, term__variable(Y),
Bindings)
)
)
).
type_unify(term__variable(X), term__functor(F, As, C), HeadTypeParams,
Bindings0, Bindings) :-
(
map__search(Bindings0, X, BindingOfX)
->
type_unify(BindingOfX, term__functor(F, As, C), HeadTypeParams,
Bindings0, Bindings)
;
\+ term__occurs_list(As, X, Bindings0),
\+ list__member(X, HeadTypeParams),
map__det_insert(Bindings0, X, term__functor(F, As, C), Bindings)
).
type_unify(term__functor(F, As, C), term__variable(X), HeadTypeParams,
Bindings0, Bindings) :-
(
map__search(Bindings0, X, BindingOfX)
->
type_unify(term__functor(F, As, C), BindingOfX, HeadTypeParams,
Bindings0, Bindings)
;
\+ term__occurs_list(As, X, Bindings0),
\+ list__member(X, HeadTypeParams),
map__det_insert(Bindings0, X, term__functor(F, As, C), Bindings)
).
type_unify(term__functor(FX, AsX, _CX), term__functor(FY, AsY, _CY),
HeadTypeParams, Bindings0, Bindings) :-
list__length(AsX, ArityX),
list__length(AsY, ArityY),
(
FX = FY,
ArityX = ArityY
->
type_unify_list(AsX, AsY, HeadTypeParams, Bindings0, Bindings)
;
fail
).
% XXX Instead of just failing if the functors' name/arity is different,
% we should check here if these types have been defined
% to be equivalent using equivalence types. But this
% is difficult because (1) it causes typevarset synchronization
% problems, and (2) the relevant variables TypeInfo, TVarSet0, TVarSet
% haven't been passed in to here.
/*******
...
;
replace_eqv_type(FX, ArityX, AsX, EqvType)
->
type_unify(EqvType, term__functor(FY, AsY, CY), HeadTypeParams,
Bindings0, Bindings)
;
replace_eqv_type(FY, ArityY, AsY, EqvType)
->
type_unify(term__functor(FX, AsX, CX), EqvType, HeadTypeParams,
Bindings0, Bindings)
;
fail
).
:- pred replace_eqv_type(const, int, list(type), type).
:- mode replace_eqv_type(in, in, in, out) is semidet.
replace_eqv_type(Functor, Arity, Args, EqvType) :-
% XXX magically_obtain(TypeTable, TVarSet0, TVarSet)
make_type_id(Functor, Arity, TypeId),
map__search(TypeTable, TypeId, TypeDefn),
TypeDefn = hlds_type_defn(TypeVarSet, TypeParams0,
eqv_type(EqvType0), _Condition, Context, _Status),
varset__merge(TVarSet0, TypeVarSet, [EqvType0 | TypeParams0],
TVarSet, [EqvType1, TypeParams1]),
type_param_to_var_list(TypeParams1, TypeParams),
term__substitute_corresponding(EqvType1, TypeParams, AsX,
EqvType).
******/
type_unify_list([], [], _) --> [].
type_unify_list([X | Xs], [Y | Ys], HeadTypeParams) -->
type_unify(X, Y, HeadTypeParams),
type_unify_list(Xs, Ys, HeadTypeParams).
:- pred type_unify_head_type_param(tvar, tvar, list(tvar), tsubst, tsubst).
:- mode type_unify_head_type_param(in, in, in, in, out) is semidet.
type_unify_head_type_param(Var, HeadVar, HeadTypeParams, Bindings0,
Bindings) :-
( map__search(Bindings0, Var, BindingOfVar) ->
BindingOfVar = term__variable(Var2),
type_unify_head_type_param(Var2, HeadVar, HeadTypeParams,
Bindings0, Bindings)
;
( Var = HeadVar ->
Bindings = Bindings0
;
\+ list__member(Var, HeadTypeParams),
map__det_insert(Bindings0, Var, term__variable(HeadVar),
Bindings)
)
).
%-----------------------------------------------------------------------------%
type_util__vars(Type, Tvars) :-
term__vars(Type, Tvars).
%-----------------------------------------------------------------------------%
apply_substitution_to_type_map(VarTypes0, Subst, VarTypes) :-
% optimize the common case of an empty type substitution
( map__is_empty(Subst) ->
VarTypes = VarTypes0
;
map__keys(VarTypes0, Vars),
apply_substitution_to_type_map_2(Vars, VarTypes0, Subst,
VarTypes)
).
:- pred apply_substitution_to_type_map_2(list(var)::in, map(var, type)::in,
tsubst::in, map(var, type)::out) is det.
apply_substitution_to_type_map_2([], VarTypes, _Subst, VarTypes).
apply_substitution_to_type_map_2([Var | Vars], VarTypes0, Subst,
VarTypes) :-
map__lookup(VarTypes0, Var, VarType0),
term__apply_substitution(VarType0, Subst, VarType),
map__det_update(VarTypes0, Var, VarType, VarTypes1),
apply_substitution_to_type_map_2(Vars, VarTypes1, Subst, VarTypes).
%-----------------------------------------------------------------------------%
apply_rec_substitution_to_type_map(VarTypes0, Subst, VarTypes) :-
% optimize the common case of an empty type substitution
( map__is_empty(Subst) ->
VarTypes = VarTypes0
;
map__keys(VarTypes0, Vars),
apply_rec_substitution_to_type_map_2(Vars, VarTypes0, Subst,
VarTypes)
).
:- pred apply_rec_substitution_to_type_map_2(list(var)::in, map(var, type)::in,
tsubst::in, map(var, type)::out) is det.
apply_rec_substitution_to_type_map_2([], VarTypes, _Subst, VarTypes).
apply_rec_substitution_to_type_map_2([Var | Vars], VarTypes0, Subst,
VarTypes) :-
map__lookup(VarTypes0, Var, VarType0),
term__apply_rec_substitution(VarType0, Subst, VarType),
map__det_update(VarTypes0, Var, VarType, VarTypes1),
apply_rec_substitution_to_type_map_2(Vars, VarTypes1, Subst, VarTypes).
%-----------------------------------------------------------------------------%
apply_substitutions_to_var_map(VarMap0, TSubst, Subst, VarMap) :-
% optimize the common case of empty substitutions
( map__is_empty(Subst), map__is_empty(TSubst) ->
VarMap = VarMap0
;
map__keys(VarMap0, TVars),
map__init(NewVarMap),
apply_substitutions_to_var_map_2(TVars, VarMap0, TSubst,
Subst, NewVarMap, VarMap)
).
:- pred apply_substitutions_to_var_map_2(list(var)::in, map(tvar,
type_info_locn)::in, tsubst::in, map(var, var)::in,
map(tvar, type_info_locn)::in,
map(tvar, type_info_locn)::out) is det.
apply_substitutions_to_var_map_2([], _VarMap0, _, _, NewVarMap, NewVarMap).
apply_substitutions_to_var_map_2([TVar | TVars], VarMap0, TSubst, Subst,
NewVarMap0, NewVarMap) :-
map__lookup(VarMap0, TVar, Locn),
type_info_locn_var(Locn, Var),
% find the new tvar, if there is one, otherwise just
% create the old var as a type variable.
( map__search(TSubst, TVar, NewTerm0) ->
NewTerm = NewTerm0
;
type_util__var(NewTerm, TVar)
),
% find the new var, if there is one
( map__search(Subst, Var, NewVar0) ->
NewVar = NewVar0
;
NewVar = Var
),
type_info_locn_set_var(Locn, NewVar, NewLocn),
% if the tvar is still a variable, insert it into the
% map with the new var.
( type_util__var(NewTerm, NewTVar) ->
map__det_insert(NewVarMap0, NewTVar, NewLocn, NewVarMap1)
;
NewVarMap1 = NewVarMap0
),
apply_substitutions_to_var_map_2(TVars, VarMap0, TSubst, Subst,
NewVarMap1, NewVarMap).
%-----------------------------------------------------------------------------%
apply_rec_subst_to_constraints(Subst, Constraints0, Constraints) :-
list__map(apply_rec_subst_to_constraint(Subst), Constraints0,
Constraints).
apply_rec_subst_to_constraint(Subst, Constraint0, Constraint) :-
Constraint0 = constraint(ClassName, Types0),
term__apply_rec_substitution_to_list(Types0, Subst, Types),
Constraint = constraint(ClassName, Types).
apply_subst_to_constraints(Subst, Constraints0, Constraints) :-
list__map(apply_subst_to_constraint(Subst), Constraints0, Constraints).
apply_subst_to_constraint(Subst, Constraint0, Constraint) :-
Constraint0 = constraint(ClassName, Types0),
term__apply_substitution_to_list(Types0, Subst, Types),
Constraint = constraint(ClassName, Types).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%