Files
mercury/compiler/typecheck.m
Fergus Henderson a8c53337ea Implement overload resolution for predicates with the same name
Estimated hours taken: 4

compiler/{typecheck.m, modes.m}:
	Implement overload resolution for predicates with the same name
	and arity that occur in different modules.

	Amough other things, this change makes it practical to define
	pred '<'(int, int) in int.m and pred '<'(float, float) in float.m,
	without having to module-qualify uses of `<'.
1996-04-07 14:20:51 +00:00

2893 lines
101 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 1995 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: typecheck.m.
% Main author: fjh.
%
% This file contains a type-checker.
%
% The predicates in this module are named as follows:
%
% Predicates that type check a particular language
% construct (goal, clause, etc.) are called typecheck_*.
% These will eventually have to iterate over every type
% assignment in the type assignment set.
%
% Predicates that unify two things with respect to a
% single type assignment, as opposed to a type assignment set
% are called type_assign_*.
%
% Access predicates for the type_info data structure are called
% type_info_*.
%
% Note that DCGS are used for THREE different purposes in this file:
%
% 1. For accumulating io__states as usual.
%
% 2. For accumulating type_infos, which contain:
% - an io_state, which is modified if we need to
% to write out an error message
% - various semi-global info which doesn't change often,
% namely the pred_id and term__context of the clause
% we are type-checking
% - a type_assign_set which stores the set of possible
% type assignments and is modified as we traverse through
% the clause
%
% 3. For accumulating type_assign_sets. This is when we are
% type-checking a single atomic construct (unification or
% predicate), and we are iterating through all the
% possible existing type-assignments to accumulate a new
% type-assignment set.
%
% This can be a little confusing if you're not aware of it, so be
% careful to look at the pred declarations to see what each DCG predicate
% is actually accumulating.
%
% There are four sorts of types:
%
% 1) discriminated unions:
% :- type tree(T) ---> nil ; t(tree(T), T, tree(T)).
%
% 2) equivalent types (treated identically, ie, same name. Any number
% of types can be equivalent; the *canonical* one is the one
% which is not defined using ==):
% :- type real == float.
%
% Currently references to equivalence types are expanded
% in a separate pass by mercury_compile.m. It would be better
% to avoid expanding them (and instead modify the type unification
% algorithm to handle equivalent types) because this would
% give better error messages. However, this is not a high
% priority.
%
% 3) higher-order predicate types
% pred, pred(T), pred(T1, T2), pred(T1, T2, T3), ...
%
% 4) builtin types
% character, int, float, string
% These types have special syntax for constants.
% There may be other types (list(T), unit, univ,
% etc.) provided by the system, but they can just
% be part of the standard library.
%
% Each predicate must have a `:- pred' declaration specifying the
% types of the arguments for that predicate.
%
%-----------------------------------------------------------------------------%
% Wish list:
%
% we should handle explicit type qualifications
% (and remove them here) but we don't do so yet
%
% we should handle equivalence types here
%
% we should handle overloading of predicates
%
% we should allow type inference for non-exported predicates
%
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- module typecheck.
:- interface.
:- import_module hlds_module, hlds_pred.
:- import_module bool, io.
:- pred typecheck(module_info, module_info, bool, io__state, io__state).
:- mode typecheck(in, out, out, di, uo) is det.
:- pred typecheck_pred_type(pred_id, pred_info, module_info,
maybe(pred_info), io__state, io__state).
:- mode typecheck_pred_type(in, in, in, out, di, uo) is det.
/*
Formally, typecheck(Module0, Module, FoundError, IO0, IO) is
intended to be true iff Module is Module0 annotated with the
variable typings that result from the process of type-checking,
FoundError is `yes' if Module0 contains any type errors and `no'
otherwise, and IO is the io__state that results from IO0 after
printing out appropriate error messages for the type errors in
Module0, if any.
Informally, typecheck(Module0, Module, FoundError, IO0, IO)
type-checks Module0 and annotates it with variable typings
(returning the result in Module), prints out appropriate error
messages, and sets FoundError to `yes' if it finds any errors
and `no' otherwise.
Typecheck also copies the clause_info structure it annotates
to the proc structures. This is done at the end of typecheck
and not at the start of modecheck because modecheck may be
reinvoked after HLDS transformations. Any transformation that
needs typechecking should work with the clause_info structure.
*/
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds_goal, hlds_data, prog_util, type_util, code_util.
:- import_module prog_io, prog_out, hlds_out, mercury_to_mercury.
:- import_module options, getopt, globals, passes_aux, clause_to_proc.
:- import_module int, list, map, string, require, std_util, tree234.
:- import_module varset, term, term_io.
%-----------------------------------------------------------------------------%
% XXX need to pass FoundError to all steps
typecheck(Module0, Module, FoundError) -->
globals__io_lookup_bool_option(statistics, Statistics),
globals__io_lookup_bool_option(verbose, Verbose),
io__stderr_stream(StdErr),
io__set_output_stream(StdErr, OldStream),
maybe_write_string(Verbose, "% Type-checking clauses...\n"),
check_pred_types(Module0, Module, FoundError),
maybe_report_stats(Statistics),
io__set_output_stream(OldStream, _).
%-----------------------------------------------------------------------------%
% Type-check the code for all the predicates in a module.
:- pred check_pred_types(module_info, module_info, bool, io__state, io__state).
:- mode check_pred_types(in, out, out, di, uo) is det.
check_pred_types(Module0, Module, FoundError) -->
{ module_info_predids(Module0, PredIds) },
typecheck_pred_types_2(PredIds, Module0, Module, no, FoundError).
%-----------------------------------------------------------------------------%
% Iterate over the list of pred_ids in a module.
:- pred typecheck_pred_types_2(list(pred_id), module_info, module_info,
bool, bool, io__state, io__state).
:- mode typecheck_pred_types_2(in, in, out, in, out, di, uo) is det.
typecheck_pred_types_2([], ModuleInfo, ModuleInfo, Error, Error) --> [].
typecheck_pred_types_2([PredId | PredIds],
ModuleInfo0, ModuleInfo, Error0, Error) -->
{ module_info_preds(ModuleInfo0, Preds0) },
{ map__lookup(Preds0, PredId, PredInfo0) },
(
{ pred_info_is_imported(PredInfo0) }
->
{ Error1 = Error0 },
{ ModuleInfo1 = ModuleInfo0 }
;
typecheck_pred_type(PredId, PredInfo0, ModuleInfo0,
MaybePredInfo),
{
MaybePredInfo = yes(PredInfo1),
Error1 = Error0,
map__set(Preds0, PredId, PredInfo1, Preds),
module_info_set_preds(ModuleInfo0, Preds, ModuleInfo1)
;
MaybePredInfo = no,
Error1 = yes,
module_info_remove_predid(ModuleInfo0, PredId,
ModuleInfo1)
}
),
typecheck_pred_types_2(PredIds, ModuleInfo1, ModuleInfo, Error1, Error).
typecheck_pred_type(PredId, PredInfo0, ModuleInfo, MaybePredInfo,
IOState0, IOState) :-
typecheck_pred_type_2(PredId, PredInfo0, ModuleInfo, MaybePredInfo0,
IOState0, IOState),
(
MaybePredInfo0 = no,
MaybePredInfo = no
;
MaybePredInfo0 = yes(PredInfo1),
maybe_add_default_mode(PredInfo1, PredInfo2),
copy_clauses_to_procs(PredInfo2, PredInfo),
MaybePredInfo = yes(PredInfo)
).
:- pred typecheck_pred_type_2(pred_id, pred_info, module_info,
maybe(pred_info), io__state, io__state).
:- mode typecheck_pred_type_2(in, in, in, out, di, uo) is det.
typecheck_pred_type_2(PredId, PredInfo0, ModuleInfo, MaybePredInfo,
IOState0, IOState) :-
(
% Compiler-generated predicates are created already type-correct,
% there's no need to typecheck them.
code_util__compiler_generated(PredInfo0)
->
pred_info_clauses_info(PredInfo0, ClausesInfo0),
ClausesInfo0 = clauses_info(_, _, _, Clauses0),
( Clauses0 = [] ->
pred_info_mark_as_external(PredInfo0, PredInfo)
;
PredInfo = PredInfo0
),
MaybePredInfo = yes(PredInfo),
IOState = IOState0
;
pred_info_arg_types(PredInfo0, _ArgTypeVarSet, ArgTypes),
pred_info_typevarset(PredInfo0, TypeVarSet0),
pred_info_clauses_info(PredInfo0, ClausesInfo0),
ClausesInfo0 = clauses_info(VarSet, VarTypes0, HeadVars, Clauses0),
(
Clauses0 = []
->
report_error_no_clauses(PredId, PredInfo0, ModuleInfo,
IOState0, IOState),
MaybePredInfo = no
;
write_progress_message("% Type-checking ",
PredId, ModuleInfo, IOState0, IOState1),
term__vars_list(ArgTypes, HeadTypeParams),
type_info_init(IOState1, ModuleInfo, PredId,
TypeVarSet0, VarSet, VarTypes0, HeadTypeParams,
TypeInfo1),
typecheck_clause_list(Clauses0, HeadVars, ArgTypes, Clauses,
TypeInfo1, TypeInfo2),
type_info_get_final_info(TypeInfo2, TypeVarSet, VarTypes1),
map__optimize(VarTypes1, VarTypes),
ClausesInfo = clauses_info(VarSet, VarTypes, HeadVars, Clauses),
pred_info_set_clauses_info(PredInfo0, ClausesInfo, PredInfo1),
pred_info_set_typevarset(PredInfo1, TypeVarSet, PredInfo),
type_info_get_found_error(TypeInfo2, Error),
(
Error = yes,
MaybePredInfo = no
;
Error = no,
MaybePredInfo = yes(PredInfo)
),
type_info_get_io_state(TypeInfo2, IOState)
)
).
%-----------------------------------------------------------------------------%
% Iterate over the list of clauses for a predicate.
:- pred typecheck_clause_list(list(clause), list(var), list(type), list(clause),
type_info, type_info).
:- mode typecheck_clause_list(in, in, in, out, type_info_di, type_info_uo)
is det.
typecheck_clause_list([], _, _, []) --> [].
typecheck_clause_list([Clause0|Clauses0], HeadVars, ArgTypes,
[Clause|Clauses]) -->
typecheck_clause(Clause0, HeadVars, ArgTypes, Clause),
typecheck_clause_list(Clauses0, HeadVars, ArgTypes, Clauses).
%-----------------------------------------------------------------------------%
% Type-check a single clause.
% As we go through a clause, we determine the possible
% type assignments for the clause. A type assignment
% is an assignment of a type to each variable in the
% clause.
%
% Note that this may cause exponential time & space usage
% in the presence of overloading of predicates and/or
% functors. This is a potentially serious problem, but
% there's no easy solution apparent.
%
% It would be more natural to use non-determinism to write
% this code, and perhaps even more efficient.
% But doing it nondeterministically would make bootstrapping more
% difficult, and most importantly would make good error
% messages very difficult.
% we should perhaps do manual garbage collection here
:- pred typecheck_clause(clause, list(var), list(type), clause,
type_info, type_info).
:- mode typecheck_clause(in, in, in, out, type_info_di, type_info_uo) is det.
typecheck_clause(Clause0, HeadVars, ArgTypes, Clause) -->
% XXX abstract clause/3
{ Clause0 = clause(Modes, Body0, Context) },
type_info_set_context(Context),
% typecheck the clause - first the head unification, and
% then the body
typecheck_var_has_type_list(HeadVars, ArgTypes, 0),
typecheck_goal(Body0, Body),
{ Clause = clause(Modes, Body, Context) },
% check for type ambiguities
typecheck_finish_clause.
%-----------------------------------------------------------------------------%
% If there are still multiple type assignments for the clause,
% then we issue an error message here.
:- pred typecheck_finish_clause(type_info, type_info).
:- mode typecheck_finish_clause(type_info_di, type_info_uo) is det.
typecheck_finish_clause(TypeInfo0, TypeInfo) :-
type_info_get_type_assign_set(TypeInfo0, TypeAssignSet),
( TypeAssignSet = [_TypeAssign] ->
TypeInfo = TypeInfo0
; TypeAssignSet = [TypeAssign1, TypeAssign2 | _] ->
% we only report an ambiguity error if
% there weren't any other errors in the clause
type_info_get_found_error(TypeInfo0, FoundError),
( FoundError = no ->
type_info_set_found_error(TypeInfo0, yes, TypeInfo1),
type_info_get_io_state(TypeInfo1, IOState0),
report_ambiguity_error(TypeInfo1, TypeAssign1,
TypeAssign2, IOState0, IOState),
type_info_set_io_state(TypeInfo1, IOState, TypeInfo)
;
TypeInfo = TypeInfo0
)
;
% there should always be a type assignment, because
% if there is an error somewhere, instead of setting
% the current type assignment set to the empty set,
% the type-checker should continue with the previous
% type assignment set (so that it can detect other
% errors in the same clause).
error("internal error in typechecker: no type-assignment"),
TypeInfo = TypeInfo0
).
/************************ BEGIN JUNK
This section is commented out, since the error which it attempts
to detect is in fact not an error at all!
% Check that the all of the types which have been inferred
% for the variables in the clause do not contain any unbound type
% variables other than the HeadTypeParams.
:- pred check_type_bindings(type_assign, type_info, type_info).
:- mode check_type_bindings(in, type_info_di, type_info_uo) is det.
check_type_bindings(TypeAssign, TypeInfo0, TypeInfo) :-
type_info_get_head_type_params(TypeInfo0, HeadTypeParams),
type_assign_get_type_bindings(TypeAssign, TypeBindings),
type_assign_get_var_types(TypeAssign, VarTypes),
map__values(VarTypes, Types),
set__init(Set0),
check_type_bindings_2(Types, TypeBindings, HeadTypeParams, Set0, Set),
set__to_sorted_list(Set, ErrorVars),
( ErrorVars = [] ->
TypeInfo = TypeInfo0
;
type_assign_get_typevarset(TypeAssign, TVarSet),
report_unresolved_type_error(ErrorVars, TVarSet, TypeInfo0,
TypeInfo)
).
:- pred check_type_bindings_2(list(term), tsubst, headtypes, set(var),
set(var)).
:- mode check_type_bindings_2(in, in, in, in, out) is det.
check_type_bindings_2([], _, _, Set, Set).
check_type_bindings_2([Type0 | Types], TypeBindings, HeadTypeParams, Set0,
Set) :-
term__apply_rec_substitution(Type0, TypeBindings, Type),
term__vars(Type, TVars),
set__list_to_set(TVars, TVarsSet0),
set__remove_list(TVarsSet0, HeadTypeParams, TVarsSet1),
set__union(Set0, TVarsSet1, Set1),
check_type_bindings_2(Types, TypeBindings, HeadTypeParams, Set1, Set).
% report an error: uninstantiated type parameter
:- pred report_unresolved_type_error(list(var), tvarset, type_info, type_info).
:- mode report_unresolved_type_error(in, in, type_info_di, type_info_uo) is det.
report_unresolved_type_error(TVars, TVarSet, TypeInfo0, TypeInfo) :-
type_info_get_io_state(TypeInfo0, IOState0),
report_unresolved_type_error_2(TypeInfo0, TVars, TVarSet,
IOState0, IOState),
type_info_set_io_state(TypeInfo0, IOState, TypeInfo1),
type_info_set_found_error(TypeInfo1, yes, TypeInfo).
:- pred report_unresolved_type_error_2(type_info, list(var), tvarset,
io__state, io__state).
:- mode report_unresolved_type_error_2(type_info_no_io, in, in, di, uo) is det.
report_unresolved_type_error_2(TypeInfo, TVars, TVarSet) -->
write_type_info_context(TypeInfo),
{ type_info_get_context(TypeInfo, Context) },
io__write_string(" type error: unresolved polymorphism.\n"),
prog_out__write_context(Context),
io__write_string(" Unbound type vars were: "),
write_type_var_list(TVars, TVarSet),
io__write_string(".\n"),
globals__io_lookup_option(verbose_errors, bool(VerboseErrors)),
( { VerboseErrors = yes } ->
io__write_string("\tThe body of the clause contains a call to a polymorphic predicate,\n"),
io__write_string("\tbut I can't determine which version should be called,\n"),
io__write_string("\tbecause the type variables listed above didn't get bound.\n"),
% XXX improve error message
io__write_string("\t(I ought to tell you which call caused the error, but I'm afraid\n"),
io__write_string("\tyou'll have to work it out yourself. My apologies.)\n")
;
[]
).
:- pred write_type_var_list(list(var), varset, io__state, io__state).
:- mode write_type_var_list(in, in, di, uo) is det.
write_type_var_list([], _) -->
io__write_string("<none>").
write_type_var_list([V|Vs], VarSet) -->
mercury_output_var(V, VarSet),
write_type_var_list_2(Vs, VarSet).
:- pred write_type_var_list_2(list(var), varset, io__state, io__state).
:- mode write_type_var_list_2(in, in, di, uo) is det.
write_type_var_list_2([], _) --> [].
write_type_var_list_2([V|Vs], VarSet) -->
io__write_string(", "),
mercury_output_var(V, VarSet),
write_type_var_list_2(Vs, VarSet).
END JUNK ***************************/
%-----------------------------------------------------------------------------%
:- pred typecheck_goal(hlds__goal, hlds__goal, type_info, type_info).
:- mode typecheck_goal(in, out, type_info_di, type_info_uo) is det.
% Typecheck a goal.
% Note that we save the context of the goal in the typeinfo for
% use in error messages. Also, if the context of the goal is empty,
% we set the context of the goal from the surrounding
% context saved in the type-info. (That should probably be done
% in make_hlds, but it was easier to do here.)
typecheck_goal(Goal0 - GoalInfo0, Goal - GoalInfo, TypeInfo0, TypeInfo) :-
goal_info_context(GoalInfo0, Context),
term__context_init(EmptyContext),
( Context = EmptyContext ->
type_info_get_context(TypeInfo0, EnclosingContext),
goal_info_set_context(GoalInfo0, EnclosingContext, GoalInfo),
TypeInfo1 = TypeInfo0
;
GoalInfo = GoalInfo0,
type_info_set_context(Context, TypeInfo0, TypeInfo1)
),
% type-check the goal
typecheck_goal_2(Goal0, Goal, TypeInfo1, TypeInfo2),
check_warn_too_much_overloading(TypeInfo2, TypeInfo).
:- pred typecheck_goal_2(hlds__goal_expr, hlds__goal_expr,
type_info, type_info).
:- mode typecheck_goal_2(in, out, type_info_di, type_info_uo) is det.
typecheck_goal_2(conj(List0), conj(List)) -->
checkpoint("conj"),
typecheck_goal_list(List0, List).
typecheck_goal_2(disj(List0), disj(List)) -->
checkpoint("disj"),
typecheck_goal_list(List0, List).
typecheck_goal_2(if_then_else(Vs, A0, B0, C0), if_then_else(Vs, A, B, C)) -->
checkpoint("if"),
typecheck_goal(A0, A),
checkpoint("then"),
typecheck_goal(B0, B),
checkpoint("else"),
typecheck_goal(C0, C).
typecheck_goal_2(not(A0), not(A)) -->
checkpoint("not"),
typecheck_goal(A0, A).
typecheck_goal_2(some(Vs, G0), some(Vs, G)) -->
checkpoint("some"),
typecheck_goal(G0, G).
typecheck_goal_2(call(_, Mode, Args, Builtin, Context, Name, Follow),
call(PredId, Mode, Args, Builtin, Context, Name, Follow)) -->
checkpoint("call"),
typecheck_call_pred(Name, Args, PredId).
typecheck_goal_2(unify(A, B0, Mode, Info, UnifyContext),
unify(A, B, Mode, Info, UnifyContext)) -->
checkpoint("unify"),
type_info_set_arg_num(0),
type_info_set_unify_context(UnifyContext),
typecheck_unification(A, B0, B).
typecheck_goal_2(switch(_, _, _), _) -->
{ error("unexpected switch") }.
% no need to typecheck pragmas
typecheck_goal_2(pragma_c_code(A,B,C,D,E), pragma_c_code(A,B,C,D,E)) --> [].
%-----------------------------------------------------------------------------%
:- pred typecheck_goal_list(list(hlds__goal), list(hlds__goal),
type_info, type_info).
:- mode typecheck_goal_list(in, out, type_info_di, type_info_uo) is det.
typecheck_goal_list([], []) --> [].
typecheck_goal_list([Goal0 | Goals0], [Goal | Goals]) -->
typecheck_goal(Goal0, Goal),
typecheck_goal_list(Goals0, Goals).
%-----------------------------------------------------------------------------%
:- pred typecheck_call_pred(sym_name, list(var), pred_id, type_info,
type_info).
:- mode typecheck_call_pred(in, in, out, type_info_di, type_info_uo) is det.
% WISHLIST - we should handle overloading of predicates
typecheck_call_pred(PredName, Args, PredId, TypeInfo0, TypeInfo) :-
list__length(Args, Arity),
PredCallId = PredName/Arity,
type_info_set_called_predid(TypeInfo0, PredCallId, TypeInfo1),
% look up the called predicate's arg types
type_info_get_module_info(TypeInfo1, ModuleInfo),
module_info_get_predicate_table(ModuleInfo, PredicateTable),
(
predicate_table_search_sym_arity(PredicateTable,
PredName, Arity, PredIdList)
->
% handle the case of a non-overloaded predicate specially
% (so that we can optimize the case of a non-overloaded,
% non-polymorphic predicate)
( PredIdList = [PredId0] ->
PredId = PredId0,
predicate_table_get_preds(PredicateTable, Preds),
map__lookup(Preds, PredId, PredInfo),
pred_info_arg_types(PredInfo, PredTypeVarSet,
PredArgTypes),
% rename apart the type variables in called
% predicate's arg types and then
% unify the types of the call arguments with
% the called predicates' arg types
% (optimize for the common case of
% a non-polymorphic predicate)
( varset__is_empty(PredTypeVarSet) ->
typecheck_var_has_type_list(Args, PredArgTypes,
0, TypeInfo1, TypeInfo)
;
typecheck_var_has_polymorphic_type_list(
Args, PredTypeVarSet, PredArgTypes,
TypeInfo1, TypeInfo)
)
;
typecheck_call_overloaded_pred(PredIdList, Args,
TypeInfo1, TypeInfo),
%
% In general, we can't figure out which predicate it
% is until after we have resolved any overloading,
% which may require type-checking the entire clause.
% Hence, for the moment, we just record an invalid
% pred_id in the HLDS. This will be rectified by
% modes.m during mode-checking; at that point,
% enough information is available to determine
% which predicate it is.
%
invalid_pred_id(PredId)
)
;
invalid_pred_id(PredId),
type_info_get_io_state(TypeInfo1, IOState0),
(
predicate_table_search_sym(PredicateTable, PredName,
OtherIds)
->
typecheck_find_arities(ModuleInfo, OtherIds, Arities),
report_error_pred_num_args(TypeInfo1, PredCallId,
Arities, IOState0, IOState)
;
report_error_undef_pred(TypeInfo1, PredCallId,
IOState0, IOState)
),
type_info_set_io_state(TypeInfo1, IOState, TypeInfo2),
type_info_set_found_error(TypeInfo2, yes, TypeInfo)
).
:- pred typecheck_find_arities(module_info, list(pred_id), list(int)).
:- mode typecheck_find_arities(in, in, out) is det.
typecheck_find_arities(_ModuleInfo, [], []).
typecheck_find_arities(ModuleInfo, [PredId | PredIds], [Arity | Arities]) :-
predicate_arity(ModuleInfo, PredId, Arity),
typecheck_find_arities(ModuleInfo, PredIds, Arities).
:- pred typecheck_call_overloaded_pred(list(pred_id), list(var),
type_info, type_info).
:- mode typecheck_call_overloaded_pred(in, in,
type_info_di, type_info_uo) is det.
typecheck_call_overloaded_pred(PredIdList, Args, TypeInfo0, TypeInfo) :-
%
% let the new arg_type_assign_set be the cross-product
% of the current type_assign_set and the set of possible
% lists of argument types for the overloaded predicate,
% suitable renamed apart
%
type_info_get_module_info(TypeInfo0, ModuleInfo),
module_info_get_predicate_table(ModuleInfo, PredicateTable),
predicate_table_get_preds(PredicateTable, Preds),
type_info_get_type_assign_set(TypeInfo0, TypeAssignSet0),
get_overloaded_pred_arg_types(PredIdList, Preds,
TypeAssignSet0, [], ArgsTypeAssignSet),
%
% then unify the types of the call arguments with the
% called predicates' arg types
%
typecheck_var_has_arg_type_list(Args, 0,
ArgsTypeAssignSet, TypeInfo0, TypeInfo).
:- pred get_overloaded_pred_arg_types(list(pred_id), pred_table,
type_assign_set, args_type_assign_set, args_type_assign_set).
:- mode get_overloaded_pred_arg_types(in, in, in, in, out) is det.
get_overloaded_pred_arg_types([], _Preds,
_TypeAssignSet0, ArgsTypeAssignSet, ArgsTypeAssignSet).
get_overloaded_pred_arg_types([PredId | PredIds], Preds,
TypeAssignSet0, ArgsTypeAssignSet0, ArgsTypeAssignSet) :-
map__lookup(Preds, PredId, PredInfo),
pred_info_arg_types(PredInfo, PredTypeVarSet, PredArgTypes),
rename_apart(TypeAssignSet0, PredTypeVarSet, PredArgTypes,
ArgsTypeAssignSet0, ArgsTypeAssignSet1),
get_overloaded_pred_arg_types(PredIds, Preds,
TypeAssignSet0, ArgsTypeAssignSet1, ArgsTypeAssignSet).
%-----------------------------------------------------------------------------%
% Rename apart the type variables in called predicate's arg types
% separately for each type assignment, resulting in an "arg type
% assignment set", and then for each arg type assignment in the
% arg type assignment set, check that the argument variables have
% the expected types.
:- pred typecheck_var_has_polymorphic_type_list(list(var), tvarset, list(type),
type_info, type_info).
:- mode typecheck_var_has_polymorphic_type_list(in, in, in,
type_info_di, type_info_uo) is det.
typecheck_var_has_polymorphic_type_list(Args, PredTypeVarSet, PredArgTypes,
TypeInfo0, TypeInfo) :-
type_info_get_type_assign_set(TypeInfo0, TypeAssignSet0),
rename_apart(TypeAssignSet0, PredTypeVarSet, PredArgTypes,
[], ArgsTypeAssignSet),
typecheck_var_has_arg_type_list(Args, 0,
ArgsTypeAssignSet, TypeInfo0, TypeInfo).
:- pred rename_apart(type_assign_set, tvarset, list(type),
args_type_assign_set, args_type_assign_set).
:- mode rename_apart(in, in, in, in, out) is det.
rename_apart([], _, _, ArgTypeAssigns, ArgTypeAssigns).
rename_apart([TypeAssign0 | TypeAssigns0], PredTypeVarSet, PredArgTypes0,
ArgTypeAssigns0, ArgTypeAssigns) :-
type_assign_rename_apart(TypeAssign0, PredTypeVarSet, PredArgTypes0,
TypeAssign, PredArgTypes),
ArgTypeAssigns1 = [TypeAssign - PredArgTypes | ArgTypeAssigns0],
rename_apart(TypeAssigns0, PredTypeVarSet, PredArgTypes0,
ArgTypeAssigns1, ArgTypeAssigns).
:- pred type_assign_rename_apart(type_assign, tvarset, list(type),
type_assign, list(type)).
:- mode type_assign_rename_apart(in, in, in, out, out) is det.
type_assign_rename_apart(TypeAssign0, PredTypeVarSet, PredArgTypes0,
TypeAssign, PredArgTypes) :-
type_assign_get_typevarset(TypeAssign0, TypeVarSet0),
varset__merge(TypeVarSet0, PredTypeVarSet, PredArgTypes0,
TypeVarSet, PredArgTypes),
type_assign_set_typevarset(TypeAssign0, TypeVarSet, TypeAssign).
%-----------------------------------------------------------------------------%
% Given a list of variables and a list of types, ensure
% that each variable has the corresponding type.
:- pred typecheck_var_has_arg_type_list(list(var), int, args_type_assign_set,
type_info, type_info).
:- mode typecheck_var_has_arg_type_list(in, in, in,
type_info_di, type_info_uo) is det.
typecheck_var_has_arg_type_list([], _, ArgTypeAssignSet,
TypeInfo0, TypeInfo) :-
convert_args_type_assign_set(ArgTypeAssignSet, TypeAssignSet),
type_info_set_type_assign_set(TypeInfo0, TypeAssignSet, TypeInfo).
typecheck_var_has_arg_type_list([Var|Vars], ArgNum, ArgTypeAssignSet0) -->
{ ArgNum1 is ArgNum + 1 },
type_info_set_arg_num(ArgNum1),
typecheck_var_has_arg_type(Var, ArgTypeAssignSet0, ArgTypeAssignSet1),
typecheck_var_has_arg_type_list(Vars, ArgNum1, ArgTypeAssignSet1).
:- pred convert_args_type_assign_set(args_type_assign_set, type_assign_set).
:- mode convert_args_type_assign_set(in, out) is det.
convert_args_type_assign_set([], []).
convert_args_type_assign_set([TypeAssign - Args | ArgTypeAssigns],
[TypeAssign | TypeAssigns]) :-
( Args = [] ->
true
;
% this should never happen, since the arguments should
% all have been processed at this point
error("convert_args_type_assign_set")
),
convert_args_type_assign_set(ArgTypeAssigns, TypeAssigns).
:- pred typecheck_var_has_arg_type(var,
args_type_assign_set, args_type_assign_set,
type_info, type_info).
:- mode typecheck_var_has_arg_type(in, in, out,
type_info_di, type_info_uo) is det.
typecheck_var_has_arg_type(VarId, ArgTypeAssignSet0, ArgTypeAssignSet,
TypeInfo0, TypeInfo) :-
type_info_get_head_type_params(TypeInfo0, HeadTypeParams),
typecheck_var_has_arg_type_2(ArgTypeAssignSet0, HeadTypeParams,
VarId, [], ArgTypeAssignSet1),
(
ArgTypeAssignSet1 = [],
ArgTypeAssignSet0 \= []
->
skip_arg(ArgTypeAssignSet0, ArgTypeAssignSet),
type_info_get_io_state(TypeInfo0, IOState0),
report_error_arg_var(TypeInfo0, VarId,
ArgTypeAssignSet0, IOState0, IOState),
type_info_set_io_state(TypeInfo0, IOState, TypeInfo1),
type_info_set_found_error(TypeInfo1, yes, TypeInfo)
;
ArgTypeAssignSet = ArgTypeAssignSet1,
TypeInfo = TypeInfo0
).
:- pred skip_arg(args_type_assign_set, args_type_assign_set).
:- mode skip_arg(in, out) is det.
skip_arg([], []).
skip_arg([TypeAssign - Args0 | ArgTypeAssigns0],
[TypeAssign - Args| ArgTypeAssigns]) :-
( Args0 = [_ | Args1] ->
Args = Args1
;
% this should never happen
error("typecheck.m: skip_arg")
),
skip_arg(ArgTypeAssigns0, ArgTypeAssigns).
:- pred typecheck_var_has_arg_type_2(args_type_assign_set, headtypes, var,
args_type_assign_set, args_type_assign_set).
:- mode typecheck_var_has_arg_type_2(in, in, in, in, out) is det.
typecheck_var_has_arg_type_2([], _, _) --> [].
typecheck_var_has_arg_type_2([TypeAssign0 - ArgTypes0 | TypeAssignSet0],
HeadTypeParams, VarId) -->
arg_type_assign_var_has_type(TypeAssign0, ArgTypes0,
HeadTypeParams, VarId),
typecheck_var_has_arg_type_2(TypeAssignSet0, HeadTypeParams, VarId).
:- pred arg_type_assign_var_has_type(type_assign, list(type), headtypes, var,
args_type_assign_set, args_type_assign_set).
:- mode arg_type_assign_var_has_type(in, in, in, in, in, out) is det.
arg_type_assign_var_has_type(TypeAssign0, ArgTypes0, HeadTypeParams, VarId,
ArgTypeAssignSet0, ArgTypeAssignSet) :-
type_assign_get_var_types(TypeAssign0, VarTypes0),
( ArgTypes0 = [Type | ArgTypes] ->
(
map__search(VarTypes0, VarId, VarType)
->
(
type_assign_unify_type(TypeAssign0, HeadTypeParams,
VarType, Type, TypeAssign1)
->
ArgTypeAssignSet = [TypeAssign1 - ArgTypes |
ArgTypeAssignSet0]
;
ArgTypeAssignSet = ArgTypeAssignSet0
)
;
map__set(VarTypes0, VarId, Type, VarTypes),
type_assign_set_var_types(TypeAssign0, VarTypes, TypeAssign),
ArgTypeAssignSet = [TypeAssign - ArgTypes | ArgTypeAssignSet0]
)
;
error("arg_type_assign_var_has_type")
).
%-----------------------------------------------------------------------------%
% Given a list of variables and a list of types, ensure
% that each variable has the corresponding type.
:- pred typecheck_var_has_type_list(list(var), list(type), int, type_info,
type_info).
:- mode typecheck_var_has_type_list(in, in, in, type_info_di, type_info_uo)
is det.
typecheck_var_has_type_list([], [_|_], _) -->
{ error("typecheck_var_has_type_list: length mismatch") }.
typecheck_var_has_type_list([_|_], [], _) -->
{ error("typecheck_var_has_type_list: length mismatch") }.
typecheck_var_has_type_list([], [], _) --> [].
typecheck_var_has_type_list([Var|Vars], [Type|Types], ArgNum) -->
{ ArgNum1 is ArgNum + 1 },
type_info_set_arg_num(ArgNum1),
typecheck_var_has_type(Var, Type),
typecheck_var_has_type_list(Vars, Types, ArgNum1).
:- pred typecheck_var_has_type(var, type, type_info, type_info).
:- mode typecheck_var_has_type(in, in, type_info_di, type_info_uo) is det.
typecheck_var_has_type(VarId, Type, TypeInfo0, TypeInfo) :-
type_info_get_type_assign_set(TypeInfo0, TypeAssignSet0),
type_info_get_head_type_params(TypeInfo0, HeadTypeParams),
typecheck_var_has_type_2(TypeAssignSet0, HeadTypeParams, VarId, Type,
[], TypeAssignSet),
(
TypeAssignSet = [],
TypeAssignSet0 \= []
->
type_info_get_io_state(TypeInfo0, IOState0),
report_error_var(TypeInfo0, VarId,
Type, TypeAssignSet0, IOState0, IOState),
type_info_set_io_state(TypeInfo0, IOState, TypeInfo1),
type_info_set_found_error(TypeInfo1, yes, TypeInfo)
;
type_info_set_type_assign_set(TypeInfo0, TypeAssignSet,
TypeInfo)
).
% Given a type assignment set and a variable id,
% return the list of possible different types for the variable.
:- type type_stuff ---> type_stuff(type, tvarset, tsubst).
:- pred get_type_stuff(type_assign_set, var, list(type_stuff)).
:- mode get_type_stuff(in, in, out) is det.
get_type_stuff([], _VarId, []).
get_type_stuff([TypeAssign | TypeAssigns], VarId, L) :-
get_type_stuff(TypeAssigns, VarId, L0),
type_assign_get_type_bindings(TypeAssign, TypeBindings),
type_assign_get_typevarset(TypeAssign, TVarSet),
type_assign_get_var_types(TypeAssign, VarTypes),
(
map__search(VarTypes, VarId, Type0)
->
Type = Type0
;
% this shouldn't happen - how can a variable which has
% not yet been assigned a type variable fail to have
% the correct type?
term__context_init(Context),
Type = term__functor(term__atom("<any>"), [], Context)
),
TypeStuff = type_stuff(Type, TVarSet, TypeBindings),
(
list__member(TypeStuff, L0)
->
L = L0
;
L = [TypeStuff | L0]
).
% Given an arg type assignment set and a variable id,
% return the list of possible different types for the argument
% and the variable.
:- type arg_type_stuff ---> arg_type_stuff(type, type, tvarset).
:- pred get_arg_type_stuff(args_type_assign_set, var, list(arg_type_stuff)).
:- mode get_arg_type_stuff(in, in, out) is det.
get_arg_type_stuff([], _VarId, []).
get_arg_type_stuff([TypeAssign - ArgTypes | ArgTypeAssigns], VarId, L) :-
get_arg_type_stuff(ArgTypeAssigns, VarId, L0),
type_assign_get_type_bindings(TypeAssign, TypeBindings),
type_assign_get_typevarset(TypeAssign, TVarSet),
type_assign_get_var_types(TypeAssign, VarTypes),
(
map__search(VarTypes, VarId, VarType0)
->
VarType = VarType0
;
% this shouldn't happen - how can a variable which has
% not yet been assigned a type variable fail to have
% the correct type?
term__context_init(Context),
VarType = term__functor(term__atom("<any>"), [], Context)
),
list__index0_det(ArgTypes, 0, ArgType),
term__apply_rec_substitution(ArgType, TypeBindings, ArgType2),
term__apply_rec_substitution(VarType, TypeBindings, VarType2),
TypeStuff = arg_type_stuff(ArgType2, VarType2, TVarSet),
(
list__member(TypeStuff, L0)
->
L = L0
;
L = [TypeStuff | L0]
).
:- type headtypes == list(tvar).
:- pred typecheck_var_has_type_2(type_assign_set, headtypes, var, type,
type_assign_set, type_assign_set).
:- mode typecheck_var_has_type_2(in, in, in, in, in, out) is det.
typecheck_var_has_type_2([], _, _, _) --> [].
typecheck_var_has_type_2([TypeAssign0 | TypeAssignSet0], HeadTypeParams, VarId,
Type) -->
type_assign_var_has_type(TypeAssign0, HeadTypeParams, VarId, Type),
typecheck_var_has_type_2(TypeAssignSet0, HeadTypeParams, VarId, Type).
:- pred type_assign_var_has_type(type_assign, headtypes, var, type,
type_assign_set, type_assign_set).
:- mode type_assign_var_has_type(in, in, in, in, in, out) is det.
type_assign_var_has_type(TypeAssign0, HeadTypeParams, VarId, Type,
TypeAssignSet0, TypeAssignSet) :-
type_assign_get_var_types(TypeAssign0, VarTypes0),
( %%% if some [VarType]
map__search(VarTypes0, VarId, VarType)
->
( %%% if some [TypeAssign1]
type_assign_unify_type(TypeAssign0, HeadTypeParams,
VarType, Type, TypeAssign1)
->
TypeAssignSet = [TypeAssign1 | TypeAssignSet0]
;
TypeAssignSet = TypeAssignSet0
)
;
map__set(VarTypes0, VarId, Type, VarTypes),
type_assign_set_var_types(TypeAssign0, VarTypes, TypeAssign),
TypeAssignSet = [TypeAssign | TypeAssignSet0]
).
%-----------------------------------------------------------------------------%
% type_assign_var_has_type_list(Vars, Types, TypeAssign, TypeInfo,
% TypeAssignSet0, TypeAssignSet):
% Let TAs = { TA | TA is a an extension of TypeAssign
% for which the types of the Vars unify with
% their respective Types },
% list__append(TAs, TypeAssignSet0, TypeAssignSet).
:- pred type_assign_var_has_type_list(list(var), list(type), type_assign,
type_info, type_assign_set, type_assign_set).
:- mode type_assign_var_has_type_list(in, in, in, type_info_ui, in, out)
is det.
type_assign_var_has_type_list([], [_|_], _, _, _, _) :-
error("type_assign_var_has_type_list: length mis-match").
type_assign_var_has_type_list([_|_], [], _, _, _, _) :-
error("type_assign_var_has_type_list: length mis-match").
type_assign_var_has_type_list([], [], TypeAssign, _,
TypeAssignSet, [TypeAssign|TypeAssignSet]).
type_assign_var_has_type_list([Arg | Args], [Type | Types], TypeAssign0,
TypeInfo, TypeAssignSet0, TypeAssignSet) :-
type_info_get_head_type_params(TypeInfo, HeadTypeParams),
type_assign_var_has_type(TypeAssign0, HeadTypeParams, Arg, Type,
[], TypeAssignSet1),
type_assign_list_var_has_type_list(TypeAssignSet1,
Args, Types, TypeInfo, TypeAssignSet0, TypeAssignSet).
% type_assign_list_var_has_type_list(TAs, Terms, Types,
% TypeInfo, TypeAssignSet0, TypeAssignSet):
% Let TAs2 = { TA | TA is a an extension of a member of TAs
% for which the types of the Terms unify with
% their respective Types },
% list__append(TAs, TypeAssignSet0, TypeAssignSet).
:- pred type_assign_list_var_has_type_list(type_assign_set, list(var),
list(type), type_info, type_assign_set, type_assign_set).
:- mode type_assign_list_var_has_type_list(in, in, in, type_info_ui, in, out)
is det.
type_assign_list_var_has_type_list([], _, _, _) --> [].
type_assign_list_var_has_type_list([TA | TAs], Args, Types, TypeInfo) -->
type_assign_var_has_type_list(Args, Types, TA, TypeInfo),
type_assign_list_var_has_type_list(TAs, Args, Types, TypeInfo).
%-----------------------------------------------------------------------------%
% Because we allow overloading, type-checking is NP-complete.
% Rather than disallow it completely, we issue a warning
% whenever "too much" overloading is used. "Too much"
% is arbitrarily defined as anthing which results in
% more than 50 possible type assignments.
:- pred check_warn_too_much_overloading(type_info, type_info).
:- mode check_warn_too_much_overloading(type_info_di, type_info_uo) is det.
check_warn_too_much_overloading(TypeInfo0, TypeInfo) :-
(
type_info_get_warned_about_overloading(TypeInfo0,
AlreadyWarned),
AlreadyWarned = no,
type_info_get_type_assign_set(TypeInfo0, TypeAssignSet),
list__length(TypeAssignSet, Count),
Count > 50
->
type_info_get_io_state(TypeInfo0, IOState0),
report_warning_too_much_overloading(TypeInfo0,
IOState0, IOState1),
type_info_set_io_state(TypeInfo0, IOState1, TypeInfo1),
type_info_set_warned_about_overloading(TypeInfo1, yes,
TypeInfo)
;
TypeInfo = TypeInfo0
).
%-----------------------------------------------------------------------------%
% used for debugging
:- pred checkpoint(string, type_info, type_info).
:- mode checkpoint(in, type_info_di, type_info_uo) is det.
checkpoint(Msg, T0, T) :-
type_info_get_io_state(T0, I0),
globals__io_lookup_bool_option(debug_types, DoCheckPoint, I0, I1),
( DoCheckPoint = yes ->
checkpoint_2(Msg, T0, I1, I)
;
I = I1
),
type_info_set_io_state(T0, I, T).
:- pred checkpoint_2(string, type_info, io__state, io__state).
:- mode checkpoint_2(in, type_info_no_io, di, uo) is det.
checkpoint_2(Msg, T0) -->
io__write_string("At "),
io__write_string(Msg),
io__write_string(": "),
globals__io_lookup_bool_option(statistics, Statistics),
maybe_report_stats(Statistics),
io__write_string("\n"),
{ type_info_get_type_assign_set(T0, TypeAssignSet) },
(
{ Statistics = yes },
{ TypeAssignSet = [TypeAssign | _] }
->
{ type_assign_get_var_types(TypeAssign, VarTypes) },
checkpoint_tree_stats("\t`var -> type' map", VarTypes),
{ type_assign_get_type_bindings(TypeAssign, TypeBindings) },
checkpoint_tree_stats("\t`type var -> type' map", TypeBindings)
;
[]
),
{ type_info_get_varset(T0, VarSet) },
write_type_assign_set(TypeAssignSet, VarSet).
:- pred checkpoint_tree_stats(string, map(_K, _V), io__state, io__state).
:- mode checkpoint_tree_stats(in, in, di, uo) is det.
checkpoint_tree_stats(Description, Tree) -->
{ tree234__count(Tree, Count) },
%{ tree234__depth(Tree, Depth) },
io__write_string(Description),
io__write_string(": count = "),
io__write_int(Count),
%io__write_string(", depth = "),
%io__write_int(Depth),
io__write_string("\n").
%-----------------------------------------------------------------------------%
% Type check a unification.
% Get the type assignment set from the type info and then just
% iterate over all the possible type assignments.
:- pred typecheck_unification(var, unify_rhs, unify_rhs, type_info, type_info).
:- mode typecheck_unification(in, in, out, type_info_di, type_info_uo) is det.
:- typecheck_unification(_, Y, _, _, _) when Y.
typecheck_unification(X, var(Y), var(Y)) -->
typecheck_unify_var_var(X, Y).
typecheck_unification(X, functor(F, As), functor(F, As)) -->
typecheck_unify_var_functor(X, F, As).
typecheck_unification(X, lambda_goal(Vars, Modes, Det, Goal0),
lambda_goal(Vars, Modes, Det, Goal)) -->
typecheck_lambda_var_has_type(X, Vars),
typecheck_goal(Goal0, Goal).
:- pred typecheck_unify_var_var(var, var, type_info, type_info).
:- mode typecheck_unify_var_var(in, in, type_info_di, type_info_uo) is det.
typecheck_unify_var_var(X, Y, TypeInfo0, TypeInfo) :-
type_info_get_type_assign_set(TypeInfo0, TypeAssignSet0),
typecheck_unify_var_var_2(TypeAssignSet0, X, Y, TypeInfo0,
[], TypeAssignSet),
( TypeAssignSet = [], TypeAssignSet0 \= [] ->
type_info_get_io_state(TypeInfo0, IOState0),
report_error_unif_var_var(TypeInfo0, X, Y, TypeAssignSet0,
IOState0, IOState1),
type_info_set_io_state(TypeInfo0, IOState1, TypeInfo1),
type_info_set_found_error(TypeInfo1, yes, TypeInfo)
;
type_info_set_type_assign_set(TypeInfo0, TypeAssignSet,
TypeInfo)
).
:- pred typecheck_unify_var_functor(var, const, list(var),
type_info, type_info).
:- mode typecheck_unify_var_functor(in, in, in, type_info_di, type_info_uo)
is det.
typecheck_unify_var_functor(Var, Functor, Args, TypeInfo0, TypeInfo) :-
%
% get the list of possible constructors that match this functor/arity
% if there aren't any, report an undefined constructor error
%
list__length(Args, Arity),
type_info_get_ctor_list(TypeInfo0, Functor, Arity, ConsDefnList),
( ConsDefnList = [] ->
type_info_get_io_state(TypeInfo0, IOState0),
report_error_undef_cons(TypeInfo0, Functor, Arity,
IOState0, IOState1),
type_info_set_io_state(TypeInfo0, IOState1, TypeInfo1),
type_info_set_found_error(TypeInfo1, yes, TypeInfo)
;
%
% produce the ConsTypeAssignSet, which is essentially the
% cross-product of the TypeAssignSet0 and the ConsDefnList
%
type_info_get_type_assign_set(TypeInfo0, TypeAssignSet0),
typecheck_unify_var_functor_get_ctors(TypeAssignSet0,
TypeInfo0, ConsDefnList, [], ConsTypeAssignSet),
( ConsTypeAssignSet = [], TypeAssignSet0 \= [] ->
% this should never happen, since undefined ctors
% should be caught by the check just above
error("typecheck_unify_var_functor: undefined cons?")
;
true
),
%
% check that the type of the functor matches the type
% of the variable
%
typecheck_functor_type( ConsTypeAssignSet, Var,
TypeInfo0, [], ArgsTypeAssignSet),
( ArgsTypeAssignSet = [], ConsTypeAssignSet \= [] ->
type_info_get_io_state(TypeInfo0, IOState0),
report_error_functor_type(TypeInfo0,
Var, ConsDefnList, Functor, Arity,
TypeAssignSet0,
IOState0, IOState1),
type_info_set_io_state(TypeInfo0, IOState1, TypeInfo1),
type_info_set_found_error(TypeInfo1, yes, TypeInfo2)
;
TypeInfo2 = TypeInfo0
),
%
% check that the type of the arguments of the functor matches
% their expected type for this functor
%
typecheck_functor_arg_types( ArgsTypeAssignSet, Args,
TypeInfo2, [], TypeAssignSet),
( TypeAssignSet = [], ArgsTypeAssignSet \= [] ->
type_info_get_io_state(TypeInfo2, IOState2),
report_error_functor_arg_types(TypeInfo2,
Var, ConsDefnList, Functor, Args,
TypeAssignSet0,
IOState2, IOState3),
type_info_set_io_state(TypeInfo2, IOState3, TypeInfo3),
type_info_set_found_error(TypeInfo3, yes, TypeInfo4)
;
TypeInfo4 = TypeInfo2
),
%
% if we encountered an error, continue checking with the
% original type assign set
%
( TypeAssignSet = [] ->
type_info_set_type_assign_set(TypeInfo4, TypeAssignSet0,
TypeInfo)
;
type_info_set_type_assign_set(TypeInfo4, TypeAssignSet,
TypeInfo)
)
).
% typecheck_unify_var_functor_get_ctors(TypeAssignSet, TypeInfo,
% ConsDefns):
%
% Iterate over all the different possible type assignments and
% constructor definitions.
% For each type assignment in `TypeAssignSet', and constructor
% definition in `ConsDefns', produce a pair
%
% TypeAssign - cons_type(Type, ArgTypes)
%
% where `cons_type(Type, ArgTypes)' records one of the possible
% types for the constructor in `ConsDefns', and where `TypeAssign' is
% the type assignment renamed apart from the types of the constructors.
:- type cons_type ---> cons_type(type, list(type)).
:- type cons_type_assign_set == list(pair(type_assign, cons_type)).
:- type args_type_assign_set == list(pair(type_assign, list(type))).
:- pred typecheck_unify_var_functor_get_ctors(type_assign_set,
type_info, list(cons_type_info),
cons_type_assign_set, cons_type_assign_set).
:- mode typecheck_unify_var_functor_get_ctors(in, in, in, in, out) is det.
% Iterate over the type assign sets
typecheck_unify_var_functor_get_ctors([], _, _) --> [].
typecheck_unify_var_functor_get_ctors([TypeAssign | TypeAssigns], TypeInfo,
ConsDefns) -->
typecheck_unify_var_functor_get_ctors_2(ConsDefns, TypeInfo,
TypeAssign),
typecheck_unify_var_functor_get_ctors(TypeAssigns, TypeInfo, ConsDefns).
% Iterate over all the different cons defns.
:- pred typecheck_unify_var_functor_get_ctors_2(list(cons_type_info), type_info,
type_assign,
cons_type_assign_set, cons_type_assign_set).
:- mode typecheck_unify_var_functor_get_ctors_2(in, in, in, in, out) is det.
typecheck_unify_var_functor_get_ctors_2([], _, _) --> [].
typecheck_unify_var_functor_get_ctors_2([ConsDefn | ConsDefns], TypeInfo,
TypeAssign0) -->
{ get_cons_stuff(ConsDefn, TypeAssign0, TypeInfo,
ConsType, ArgTypes, TypeAssign1) },
list__append([TypeAssign1 - cons_type(ConsType, ArgTypes)]),
typecheck_unify_var_functor_get_ctors_2(ConsDefns, TypeInfo,
TypeAssign0).
% typecheck_functor_type(ConsTypeAssignSet, Var, ...):
%
% For each possible cons type assignment in `ConsTypeAssignSet',
% for each possible constructor type,
% check that the type of `Var' matches this type.
:- pred typecheck_functor_type(cons_type_assign_set, var, type_info,
args_type_assign_set, args_type_assign_set).
:- mode typecheck_functor_type(in, in, type_info_ui, in, out) is det.
typecheck_functor_type([], _, _) --> [].
typecheck_functor_type([TypeAssign - ConsType | ConsTypeAssigns],
Var, TypeInfo) -->
{ ConsType = cons_type(Type, ArgTypes) },
type_assign_check_functor_type(Type, ArgTypes, Var,
TypeAssign, TypeInfo),
typecheck_functor_type(ConsTypeAssigns, Var, TypeInfo).
% typecheck_functor_arg_types(ConsTypeAssignSet, Var, Args, ...):
%
% For each possible cons type assignment in `ConsTypeAssignSet',
% for each possible constructor argument types,
% check that the types of `Args' matches these types.
:- pred typecheck_functor_arg_types(args_type_assign_set, list(var),
type_info, type_assign_set, type_assign_set).
:- mode typecheck_functor_arg_types(in, in, type_info_ui, in, out)
is det.
typecheck_functor_arg_types([], _, _) --> [].
typecheck_functor_arg_types([TypeAssign - ArgTypes | ConsTypeAssigns],
Args, TypeInfo) -->
type_assign_var_has_type_list(Args, ArgTypes, TypeAssign, TypeInfo),
typecheck_functor_arg_types(ConsTypeAssigns, Args, TypeInfo).
% iterate over all the possible type assignments.
:- pred typecheck_unify_var_var_2(type_assign_set, var, var,
type_info, type_assign_set, type_assign_set).
:- mode typecheck_unify_var_var_2(in, in, in, type_info_ui, in, out) is det.
typecheck_unify_var_var_2([], _, _, _) --> [].
typecheck_unify_var_var_2([TypeAssign0 | TypeAssigns0], X, Y, TypeInfo) -->
type_assign_unify_var_var(X, Y, TypeAssign0, TypeInfo),
typecheck_unify_var_var_2(TypeAssigns0, X, Y, TypeInfo).
%-----------------------------------------------------------------------------%
% Type-check the unification of two variables,
% and update the type assignment.
% TypeAssign0 is the type assignment we are updating,
% TypeAssignSet0 is an accumulator for the list of possible
% type assignments so far, and TypeAssignSet is TypeAssignSet plus
% any type assignment(s) resulting from TypeAssign0 and this
% unification.
:- pred type_assign_unify_var_var(var, var, type_assign, type_info,
type_assign_set, type_assign_set).
:- mode type_assign_unify_var_var(in, in, in, type_info_ui, in, out) is det.
type_assign_unify_var_var(X, Y, TypeAssign0, TypeInfo, TypeAssignSet0,
TypeAssignSet) :-
type_assign_get_var_types(TypeAssign0, VarTypes0),
(
map__search(VarTypes0, X, TypeX)
->
(
map__search(VarTypes0, Y, TypeY)
->
% both X and Y already have types - just
% unify their types
type_info_get_head_type_params(TypeInfo,
HeadTypeParams),
(
type_assign_unify_type(TypeAssign0,
HeadTypeParams, TypeX, TypeY,
TypeAssign3)
->
TypeAssignSet = [TypeAssign3 | TypeAssignSet0]
;
TypeAssignSet = TypeAssignSet0
)
;
% Y is a fresh variable which hasn't been
% assigned a type yet
map__set(VarTypes0, Y, TypeX, VarTypes),
type_assign_set_var_types(TypeAssign0, VarTypes,
TypeAssign),
TypeAssignSet = [TypeAssign | TypeAssignSet0]
)
;
(
map__search(VarTypes0, Y, TypeY)
->
% X is a fresh variable which hasn't been
% assigned a type yet
map__set(VarTypes0, X, TypeY, VarTypes),
type_assign_set_var_types(TypeAssign0, VarTypes,
TypeAssign),
TypeAssignSet = [TypeAssign | TypeAssignSet0]
;
% both X and Y are fresh variables -
% introduce a fresh type variable to represent
% their type
type_assign_get_typevarset(TypeAssign0, TypeVarSet0),
varset__new_var(TypeVarSet0, TypeVar, TypeVarSet),
type_assign_set_typevarset(TypeAssign0, TypeVarSet,
TypeAssign1),
Type = term__variable(TypeVar),
map__set(VarTypes0, X, Type, VarTypes1),
map__set(VarTypes1, Y, Type, VarTypes),
type_assign_set_var_types(TypeAssign1, VarTypes,
TypeAssign),
TypeAssignSet = [TypeAssign | TypeAssignSet0]
)
).
%-----------------------------------------------------------------------------%
:- pred type_assign_check_functor_type(type, list(type),
var, type_assign, type_info,
args_type_assign_set, args_type_assign_set).
:- mode type_assign_check_functor_type(in, in, in, in, type_info_ui,
in, out) is det.
type_assign_check_functor_type(ConsType, ArgTypes, Y, TypeAssign1,
TypeInfo, TypeAssignSet0, TypeAssignSet) :-
% unify the type of Var with the type of the constructor
type_assign_get_var_types(TypeAssign1, VarTypes0),
( %%% if some [TypeY]
map__search(VarTypes0, Y, TypeY)
->
type_info_get_head_type_params(TypeInfo, HeadTypeParams),
( %%% if some [TypeAssign2]
type_assign_unify_type(TypeAssign1, HeadTypeParams,
ConsType, TypeY, TypeAssign2)
->
TypeAssignSet = [TypeAssign2 - ArgTypes |
TypeAssignSet0]
;
TypeAssignSet = TypeAssignSet0
)
;
map__set(VarTypes0, Y, ConsType, VarTypes),
type_assign_set_var_types(TypeAssign1, VarTypes, TypeAssign3),
TypeAssignSet = [TypeAssign3 - ArgTypes | TypeAssignSet0]
).
%-----------------------------------------------------------------------------%
% Given an cons_type_info, construct a type for the
% constructor and a list of types of the arguments,
% suitable renamed apart from the current type_assign's
% typevarset.
:- pred get_cons_stuff(cons_type_info, type_assign, type_info,
type, list(type), type_assign).
:- mode get_cons_stuff(in, in, in, out, out, out) is det.
get_cons_stuff(ConsDefn, TypeAssign0, _TypeInfo, ConsType, ArgTypes,
TypeAssign) :-
ConsDefn = cons_type_info(ConsTypeVarSet, ConsType0, ArgTypes0),
% Rename apart the type vars in the type of the constructor
% and the types of its arguments.
% (Optimize the common case of a non-polymorphic type)
( ConsType0 = term__functor(_, [], _) ->
ConsType = ConsType0,
ArgTypes = ArgTypes0,
TypeAssign = TypeAssign0
;
type_assign_rename_apart(TypeAssign0, ConsTypeVarSet,
[ConsType0 | ArgTypes0],
TypeAssign1, [ConsType1 | ArgTypes1])
->
ConsType = ConsType1,
ArgTypes = ArgTypes1,
TypeAssign = TypeAssign1
;
error("get_cons_stuff: type_assign_rename_apart failed")
).
%-----------------------------------------------------------------------------%
% typecheck_lambda_var_has_type(Var, ArgVars, ...)
% checks that `Var' has type `pred(T1, T2, ...)' where
% T1, T2, ... are the types of the `ArgVars'.
:- pred typecheck_lambda_var_has_type(var, list(var), type_info, type_info).
:- mode typecheck_lambda_var_has_type(in, in, type_info_di, type_info_uo)
is det.
typecheck_lambda_var_has_type(Var, ArgVars, TypeInfo0, TypeInfo) :-
type_info_get_type_assign_set(TypeInfo0, TypeAssignSet0),
type_info_get_head_type_params(TypeInfo0, HeadTypeParams),
typecheck_lambda_var_has_type_2(TypeAssignSet0, HeadTypeParams,
Var, ArgVars, [], TypeAssignSet),
(
TypeAssignSet = [],
TypeAssignSet0 \= []
->
type_info_get_io_state(TypeInfo0, IOState0),
report_error_lambda_var(TypeInfo0, Var, ArgVars, TypeAssignSet0,
IOState0, IOState),
type_info_set_io_state(TypeInfo0, IOState, TypeInfo1),
type_info_set_found_error(TypeInfo1, yes, TypeInfo)
;
type_info_set_type_assign_set(TypeInfo0, TypeAssignSet,
TypeInfo)
).
:- pred typecheck_lambda_var_has_type_2(type_assign_set, headtypes,
var, list(var),
type_assign_set, type_assign_set).
:- mode typecheck_lambda_var_has_type_2(in, in, in, in, in, out) is det.
typecheck_lambda_var_has_type_2([], _, _, _) --> [].
typecheck_lambda_var_has_type_2([TypeAssign0 | TypeAssignSet0],
HeadTypeParams, Var, ArgVars) -->
{ type_assign_get_types_of_vars(ArgVars, TypeAssign0, ArgVarTypes,
TypeAssign1) },
{ term__context_init(Context) },
{ LambdaType = term__functor(term__atom("pred"), ArgVarTypes,
Context) },
type_assign_var_has_type(TypeAssign1, HeadTypeParams, Var, LambdaType),
typecheck_lambda_var_has_type_2(TypeAssignSet0, HeadTypeParams,
Var, ArgVars).
:- pred type_assign_get_types_of_vars(list(var), type_assign, list(type),
type_assign).
:- mode type_assign_get_types_of_vars(in, in, out, out) is det.
type_assign_get_types_of_vars([], TypeAssign, [], TypeAssign).
type_assign_get_types_of_vars([Var|Vars], TypeAssign0,
[Type|Types], TypeAssign) :-
% check whether the variable already has a type
type_assign_get_var_types(TypeAssign0, VarTypes0),
( map__search(VarTypes0, Var, VarType) ->
% if so, use that type
Type = VarType,
TypeAssign2 = TypeAssign0
;
% otherwise, introduce a fresh type variable to
% use as the type of that variable
type_assign_get_typevarset(TypeAssign0, TypeVarSet0),
varset__new_var(TypeVarSet0, TypeVar, TypeVarSet),
type_assign_set_typevarset(TypeAssign0, TypeVarSet,
TypeAssign1),
Type = term__variable(TypeVar),
map__det_insert(VarTypes0, Var, Type, VarTypes1),
type_assign_set_var_types(TypeAssign1, VarTypes1, TypeAssign2)
),
% recursively process the rest of the variables.
type_assign_get_types_of_vars(Vars, TypeAssign2, Types, TypeAssign).
%-----------------------------------------------------------------------------%
% Unify (with occurs check) two types in a type assignment
% and update the type bindings.
:- pred type_assign_unify_type(type_assign, headtypes, type, type, type_assign).
:- mode type_assign_unify_type(in, in, in, in, out) is semidet.
type_assign_unify_type(TypeAssign0, HeadTypeParams, X, Y, TypeAssign) :-
type_assign_get_type_bindings(TypeAssign0, TypeBindings0),
type_unify(X, Y, HeadTypeParams, TypeBindings0, TypeBindings),
type_assign_set_type_bindings(TypeAssign0, TypeBindings, TypeAssign).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% builtin_atomic_type(Const, TypeName)
% If Const is a constant of a builtin atomic type,
% instantiates TypeName to the name of that type,
% otherwise fails.
:- pred builtin_atomic_type(const, string).
:- mode builtin_atomic_type(in, out) is semidet.
builtin_atomic_type(term__integer(_), "int").
builtin_atomic_type(term__float(_), "float").
builtin_atomic_type(term__string(_), "string").
builtin_atomic_type(term__atom(String), "character") :-
string__char_to_string(_, String).
% builtin_pred_type(TypeInfo, Functor, Arity, PredConsInfoList) :
% If Functor/Arity is a constant of a pred type,
% instantiates the output parameters, otherwise fails.
%
% Instantiates PredConsInfoList to the set of cons_type_info
% structures for each predicate with name `Functor' and arity
% greater than or equal to Arity.
%
% For example, functor `map__search/1' has type `pred(K,V)'
% (hence PredTypeParams = [K,V]) and argument types [map(K,V)].
:- pred builtin_pred_type(type_info, const, int, list(cons_type_info)).
:- mode builtin_pred_type(type_info_ui, in, in, out)
is semidet.
builtin_pred_type(TypeInfo, Functor, Arity, PredConsInfoList) :-
Functor = term__atom(Name),
type_info_get_module_info(TypeInfo, ModuleInfo),
module_info_get_predicate_table(ModuleInfo, PredicateTable),
( predicate_table_search_name(PredicateTable, Name, PredIdList) ->
predicate_table_get_preds(PredicateTable, Preds),
make_pred_cons_info_list(PredIdList, Preds, Arity,
ModuleInfo, [], PredConsInfoList)
;
PredConsInfoList = []
).
:- pred make_pred_cons_info_list(list(pred_id), pred_table, int, module_info,
list(cons_type_info), list(cons_type_info)).
:- mode make_pred_cons_info_list(in, in, in, in, in, out) is det.
make_pred_cons_info_list([], _PredTable, _Arity, _ModuleInfo, L, L).
make_pred_cons_info_list([PredId|PredIds], PredTable, Arity, ModuleInfo,
L0, L) :-
make_pred_cons_info(PredId, PredTable, Arity, ModuleInfo, L0, L1),
make_pred_cons_info_list(PredIds, PredTable, Arity, ModuleInfo, L1, L).
:- type cons_type_info ---> cons_type_info(tvarset, type, list(type)).
:- pred make_pred_cons_info(pred_id, pred_table, int, module_info,
list(cons_type_info), list(cons_type_info)).
:- mode make_pred_cons_info(in, in, in, in, in, out) is det.
make_pred_cons_info(PredId, PredTable, FuncArity, _ModuleInfo, L0, L) :-
map__lookup(PredTable, PredId, PredInfo),
pred_info_arity(PredInfo, PredArity),
pred_info_get_is_pred_or_func(PredInfo, IsPredOrFunc),
(
IsPredOrFunc = predicate,
PredArity >= FuncArity
->
pred_info_arg_types(PredInfo, PredTypeVarSet, CompleteArgTypes),
(
list__split_list(FuncArity, CompleteArgTypes,
ArgTypes, PredTypeParams)
->
term__context_init("<builtin>", 0, Context),
PredType = term__functor(term__atom("pred"),
PredTypeParams, Context),
ConsInfo = cons_type_info(PredTypeVarSet, PredType,
ArgTypes),
L = [ConsInfo | L0]
;
error("make_pred_cons_info: split_list failed")
)
;
IsPredOrFunc = function,
PredAsFuncArity is PredArity - 1,
PredAsFuncArity >= FuncArity
->
pred_info_arg_types(PredInfo, PredTypeVarSet, CompleteArgTypes),
(
list__split_list(FuncArity, CompleteArgTypes,
FuncArgTypes, FuncTypeParams),
list__length(FuncTypeParams, NumParams0),
NumParams1 is NumParams0 - 1,
list__split_list(NumParams1, FuncTypeParams,
FuncArgTypeParams, [FuncReturnTypeParam])
->
( FuncArgTypeParams = [] ->
FuncType = FuncReturnTypeParam
;
term__context_init("<builtin>", 0, Context),
FuncType = term__functor(term__atom("="), [
term__functor(term__atom("func"),
FuncArgTypeParams, Context),
FuncReturnTypeParam
], Context)
),
ConsInfo = cons_type_info(PredTypeVarSet, FuncType,
FuncArgTypes),
L = [ConsInfo | L0]
;
error("make_pred_cons_info: split_list or remove_suffix failed")
)
;
L = L0
).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% The type_info data structure and access predicates.
:- type type_info
---> type_info(
io__state, % The io state
module_info, % The global symbol tables
pred_call_id, % The pred_call_id of the pred
% being called (if any)
int, % The argument number within
% a pred call
pred_id, % The pred we're checking
term__context, % The context of the goal
% we're checking
unify_context, % The original source of the
% unification we're checking
varset, % Variable names
type_assign_set,
% This is the main piece of
% information that we are
% computing and which gets
% updated as we go along
bool, % did we find any type errors?
headtypes, % Head type params
bool % Have we already warned about
% highly ambiguous overloading?
).
% The normal inst of a type_info struct: ground, with
% the io_state and the struct itself unique, but with
% multiple references allowed for the other parts.
/*
:- inst uniq_type_info = bound_unique(
type_info(
unique, ground,
ground, ground, ground, ground,
ground, ground, ground, ground,
ground, ground
)
).
*/
:- inst uniq_type_info = ground.
:- mode type_info_uo :: (free -> uniq_type_info).
:- mode type_info_ui :: (uniq_type_info -> uniq_type_info).
:- mode type_info_di :: (uniq_type_info -> dead).
% Some fiddly modes used when we want to extract
% the io_state from a type_info struct and then put it back again.
/*
:- inst type_info_no_io = bound_unique(
type_info(
dead, ground,
ground, ground, ground, ground,
ground, ground, ground, ground,
ground, ground
)
).
*/
:- inst type_info_no_io = ground.
:- mode type_info_get_io_state :: (uniq_type_info -> type_info_no_io).
:- mode type_info_no_io :: (type_info_no_io -> type_info_no_io).
:- mode type_info_set_io_state :: (type_info_no_io -> dead).
%-----------------------------------------------------------------------------%
:- pred type_info_init(io__state, module_info, pred_id, varset,
varset, map(var, type), headtypes, type_info).
:- mode type_info_init(di, in, in, in, in, in, in, type_info_uo) is det.
type_info_init(IOState0, ModuleInfo, PredId, TypeVarSet, VarSet,
VarTypes, HeadTypeParams, TypeInfo) :-
CallPredId = unqualified("") / 0,
term__context_init(Context),
map__init(TypeBindings),
FoundTypeError = no,
WarnedAboutOverloading = no,
copy(IOState0, IOState), % XXX
TypeInfo = type_info(
IOState, ModuleInfo, CallPredId, 0, PredId, Context,
unify_context(explicit, []),
VarSet, [type_assign(VarTypes, TypeVarSet, TypeBindings)],
FoundTypeError, HeadTypeParams, WarnedAboutOverloading
).
%-----------------------------------------------------------------------------%
:- pred type_info_get_io_state(type_info, io__state).
:- mode type_info_get_io_state(type_info_get_io_state, uo) is det.
type_info_get_io_state(type_info(IOState0,_,_,_,_,_,_,_,_,_,_,_), IOState) :-
copy(IOState0, IOState). % XXX
%-----------------------------------------------------------------------------%
:- pred type_info_set_io_state(type_info, io__state, type_info).
:- mode type_info_set_io_state(type_info_set_io_state, di, type_info_uo) is det.
type_info_set_io_state( type_info(_,B,C,D,E,F,G,H,I,J,K,L), IOState0,
type_info(IOState,B,C,D,E,F,G,H,I,J,K,L)) :-
copy(IOState0, IOState). % XXX
%-----------------------------------------------------------------------------%
:- pred type_info_get_module_name(type_info, string).
:- mode type_info_get_module_name(in, out) is det.
type_info_get_module_name(type_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_), Name) :-
module_info_name(ModuleInfo, Name).
%-----------------------------------------------------------------------------%
:- pred type_info_get_module_info(type_info, module_info).
:- mode type_info_get_module_info(in, out) is det.
type_info_get_module_info(type_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_),
ModuleInfo).
%-----------------------------------------------------------------------------%
:- pred type_info_get_preds(type_info, predicate_table).
:- mode type_info_get_preds(in, out) is det.
type_info_get_preds(type_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_), Preds) :-
module_info_get_predicate_table(ModuleInfo, Preds).
%-----------------------------------------------------------------------------%
:- pred type_info_get_types(type_info, type_table).
:- mode type_info_get_types(in, out) is det.
type_info_get_types(type_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_), Types) :-
module_info_types(ModuleInfo, Types).
%-----------------------------------------------------------------------------%
:- pred type_info_get_ctors(type_info, cons_table).
:- mode type_info_get_ctors(in, out) is det.
type_info_get_ctors(type_info(_,ModuleInfo,_,_,_,_,_,_,_,_,_,_), Ctors) :-
module_info_ctors(ModuleInfo, Ctors).
%-----------------------------------------------------------------------------%
:- pred type_info_get_called_predid(type_info, pred_call_id).
:- mode type_info_get_called_predid(in, out) is det.
type_info_get_called_predid(type_info(_,_,PredId,_,_,_,_,_,_,_,_,_), PredId).
%-----------------------------------------------------------------------------%
:- pred type_info_set_called_predid(type_info, pred_call_id, type_info).
:- mode type_info_set_called_predid(type_info_di, in, type_info_uo) is det.
type_info_set_called_predid(type_info(A,B,_,D,E,F,G,H,I,J,K,L), PredCallId,
type_info(A,B,PredCallId,D,E,F,G,H,I,J,K,L)).
%-----------------------------------------------------------------------------%
:- pred type_info_get_arg_num(type_info, int).
:- mode type_info_get_arg_num(in, out) is det.
type_info_get_arg_num(type_info(_,_,_,ArgNum,_,_,_,_,_,_,_,_), ArgNum).
%-----------------------------------------------------------------------------%
:- pred type_info_set_arg_num(int, type_info, type_info).
:- mode type_info_set_arg_num(in, type_info_di, type_info_uo) is det.
type_info_set_arg_num(ArgNum, type_info(A,B,C,_, E,F,G,H,I,J,K,L),
type_info(A,B,C,ArgNum,E,F,G,H,I,J,K,L)).
%-----------------------------------------------------------------------------%
:- pred type_info_get_predid(type_info, pred_id).
:- mode type_info_get_predid(in, out) is det.
type_info_get_predid(type_info(_,_,_,_,PredId,_,_,_,_,_,_,_), PredId).
%-----------------------------------------------------------------------------%
:- pred type_info_get_context(type_info, term__context).
:- mode type_info_get_context(in, out) is det.
type_info_get_context(type_info(_,_,_,_,_,Context,_,_,_,_,_,_), Context).
%-----------------------------------------------------------------------------%
:- pred type_info_set_context(term__context, type_info, type_info).
:- mode type_info_set_context(in, type_info_di, type_info_uo) is det.
type_info_set_context(Context, type_info(A,B,C,D,E,_,G,H,I,J,K,L),
type_info(A,B,C,D,E,Context,G,H,I,J,K,L)).
%-----------------------------------------------------------------------------%
:- pred type_info_get_unify_context(type_info, unify_context).
:- mode type_info_get_unify_context(in, out) is det.
type_info_get_unify_context(type_info(_,_,_,_,_,_,UnifyContext,_,_,_,_,_),
UnifyContext).
%-----------------------------------------------------------------------------%
:- pred type_info_set_unify_context(unify_context, type_info, type_info).
:- mode type_info_set_unify_context(in, type_info_di, type_info_uo) is det.
type_info_set_unify_context(UnifyContext, type_info(A,B,C,D,E,F,_,H,I,J,K,L),
type_info(A,B,C,D,E,F,UnifyContext,H,I,J,K,L)).
%-----------------------------------------------------------------------------%
:- pred type_info_get_varset(type_info, varset).
:- mode type_info_get_varset(in, out) is det.
type_info_get_varset(type_info(_,_,_,_,_,_,_,VarSet,_,_,_,_), VarSet).
%-----------------------------------------------------------------------------%
:- pred type_info_get_type_assign_set(type_info, type_assign_set).
:- mode type_info_get_type_assign_set(in, out) is det.
type_info_get_type_assign_set(type_info(_,_,_,_,_,_,_,_,TypeAssignSet,_,_,_),
TypeAssignSet).
%-----------------------------------------------------------------------------%
:- pred type_info_get_final_info(type_info, tvarset, map(var, type)).
:- mode type_info_get_final_info(in, out, out) is det.
type_info_get_final_info(TypeInfo, TypeVarSet, VarTypes) :-
type_info_get_type_assign_set(TypeInfo, TypeAssignSet),
( TypeAssignSet = [TypeAssign | _] ->
type_assign_get_typevarset(TypeAssign, TypeVarSet),
type_assign_get_var_types(TypeAssign, VarTypes0),
type_assign_get_type_bindings(TypeAssign, TypeBindings),
map__keys(VarTypes0, Vars),
expand_types(Vars, TypeBindings, VarTypes0, VarTypes)
;
error("internal error in type_info_get_vartypes")
).
% fully expand the types of the variables by applying the type
% bindings
:- pred expand_types(list(var), tsubst, map(var, type), map(var, type)).
:- mode expand_types(in, in, in, out) is det.
expand_types([], _, VarTypes, VarTypes).
expand_types([Var | Vars], TypeSubst, VarTypes0, VarTypes) :-
map__lookup(VarTypes0, Var, Type0),
term__apply_rec_substitution(Type0, TypeSubst, Type),
map__set(VarTypes0, Var, Type, VarTypes1),
expand_types(Vars, TypeSubst, VarTypes1, VarTypes).
%-----------------------------------------------------------------------------%
:- pred type_info_set_type_assign_set(type_info, type_assign_set, type_info).
:- mode type_info_set_type_assign_set(type_info_di, in, type_info_uo) is det.
type_info_set_type_assign_set( type_info(A,B,C,D,E,F,G,H,_,J,K,L),
TypeAssignSet, type_info(A,B,C,D,E,F,G,H,TypeAssignSet,J,K,L)).
%-----------------------------------------------------------------------------%
:- pred type_info_get_found_error(type_info, bool).
:- mode type_info_get_found_error(type_info_ui, out) is det.
type_info_get_found_error(type_info(_,_,_,_,_,_,_,_,_,FoundError,_,_),
FoundError).
%-----------------------------------------------------------------------------%
:- pred type_info_set_found_error(type_info, bool, type_info).
:- mode type_info_set_found_error(type_info_di, in, type_info_uo) is det.
type_info_set_found_error( type_info(A,B,C,D,E,F,G,H,I,_,K,L), FoundError,
type_info(A,B,C,D,E,F,G,H,I,FoundError,K,L)).
%-----------------------------------------------------------------------------%
:- pred type_info_get_head_type_params(type_info, headtypes).
:- mode type_info_get_head_type_params(type_info_ui, out) is det.
type_info_get_head_type_params( type_info(_,_,_,_,_,_,_,_,_,_,HeadTypeParams,_),
HeadTypeParams).
%-----------------------------------------------------------------------------%
:- pred type_info_set_head_type_params(type_info, headtypes, type_info).
:- mode type_info_set_head_type_params(type_info_di, in, type_info_uo) is det.
type_info_set_head_type_params( type_info(A,B,C,D,E,F,G,H,I,J,_,L),
HeadTypeParams,
type_info(A,B,C,D,E,F,G,H,I,J,HeadTypeParams,L)).
%-----------------------------------------------------------------------------%
:- pred type_info_get_warned_about_overloading(type_info, bool).
:- mode type_info_get_warned_about_overloading(type_info_ui, out) is det.
type_info_get_warned_about_overloading(type_info(_,_,_,_,_,_,_,_,_,_,_,Warned),
Warned).
%-----------------------------------------------------------------------------%
:- pred type_info_set_warned_about_overloading(type_info, bool, type_info).
:- mode type_info_set_warned_about_overloading(type_info_di, in, type_info_uo)
is det.
type_info_set_warned_about_overloading( type_info(A,B,C,D,E,F,G,H,I,J,K,_),
Warned,
type_info(A,B,C,D,E,F,G,H,I,J,K,Warned)).
%-----------------------------------------------------------------------------%
:- pred type_info_get_ctor_list(type_info, const, int, list(cons_type_info)).
:- mode type_info_get_ctor_list(type_info_ui, in, in, out) is det.
type_info_get_ctor_list(TypeInfo, Functor, Arity, ConsInfoList) :-
% Check if `Functor/Arity' has been defined as a constructor
% in some discriminated union type(s). This gives
% us a list of possible cons_type_infos.
type_info_get_ctors(TypeInfo, Ctors),
(
Functor = term__atom(Name),
map__search(Ctors, cons(Name, Arity), HLDS_ConsDefnList)
->
convert_cons_defn_list(TypeInfo, HLDS_ConsDefnList,
ConsInfoList0)
;
ConsInfoList0 = []
),
% Check if Functor is a constant of one of the builtin atomic
% types (string, float, int, character). If so, insert
% the resulting cons_type_info at the start of the list.
(
Arity = 0,
builtin_atomic_type(Functor, BuiltInTypeName)
->
term__context_init("<builtin>", 0, Context),
ConsType = term__functor(term__atom(BuiltInTypeName), [],
Context),
varset__init(ConsTypeVarSet),
ConsInfo = cons_type_info(ConsTypeVarSet, ConsType, []),
ConsInfoList1 = [ConsInfo | ConsInfoList0]
;
ConsInfoList1 = ConsInfoList0
),
% Check if Functor is the name of a predicate which takes at least
% Arity arguments. If so, insert the resulting cons_type_info
% at the start of the list.
(
builtin_pred_type(TypeInfo, Functor, Arity, PredConsInfoList)
->
list__append(ConsInfoList1, PredConsInfoList, ConsInfoList)
;
ConsInfoList = ConsInfoList1
).
:- pred convert_cons_defn_list(type_info, list(hlds__cons_defn),
list(cons_type_info)).
:- mode convert_cons_defn_list(type_info_ui, in, out) is det.
:- convert_cons_defn_list(_, L, _) when L. % NU-Prolog indexing.
convert_cons_defn_list(_TypeInfo, [], []).
convert_cons_defn_list(TypeInfo, [X|Xs], [Y|Ys]) :-
convert_cons_defn(TypeInfo, X, Y),
convert_cons_defn_list(TypeInfo, Xs, Ys).
:- pred convert_cons_defn(type_info, hlds__cons_defn, cons_type_info).
:- mode convert_cons_defn(type_info_ui, in, out) is det.
convert_cons_defn(TypeInfo, HLDS_ConsDefn, ConsTypeInfo) :-
HLDS_ConsDefn = hlds__cons_defn(ArgTypes, TypeId, Context),
type_info_get_types(TypeInfo, Types),
map__lookup(Types, TypeId, TypeDefn),
TypeDefn = hlds__type_defn(ConsTypeVarSet, ConsTypeParams, _, _, _),
TypeId = QualifiedName - _Arity,
unqualify_name(QualifiedName, Name),
ConsType = term__functor(term__atom(Name), ConsTypeParams, Context),
ConsTypeInfo = cons_type_info(ConsTypeVarSet, ConsType, ArgTypes).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% The type_assign and type_assign_set data structures.
:- type type_assign_set == list(type_assign).
:- type type_assign ---> type_assign(
map(var, type), % var types
tvarset, % type names
tsubst % type bindings
).
%-----------------------------------------------------------------------------%
% Access predicates for the type_assign data structure.
% Excruciatingly boring code.
:- pred type_assign_get_var_types(type_assign, map(var, type)).
:- mode type_assign_get_var_types(in, out) is det.
type_assign_get_var_types(type_assign(VarTypes, _, _), VarTypes).
%-----------------------------------------------------------------------------%
:- pred type_assign_get_typevarset(type_assign, tvarset).
:- mode type_assign_get_typevarset(in, out) is det.
type_assign_get_typevarset(type_assign(_, TypeVarSet, _), TypeVarSet).
%-----------------------------------------------------------------------------%
:- pred type_assign_get_type_bindings(type_assign, tsubst).
:- mode type_assign_get_type_bindings(in, out) is det.
type_assign_get_type_bindings(type_assign(_, _, TypeBindings), TypeBindings).
%-----------------------------------------------------------------------------%
:- pred type_assign_set_var_types(type_assign, map(var, type), type_assign).
:- mode type_assign_set_var_types(in, in, out) is det.
type_assign_set_var_types(type_assign(_, B, C), VarTypes,
type_assign(VarTypes, B, C)).
%-----------------------------------------------------------------------------%
:- pred type_assign_set_typevarset(type_assign, tvarset, type_assign).
:- mode type_assign_set_typevarset(in, in, out) is det.
type_assign_set_typevarset(type_assign(A, _, C), TypeVarSet,
type_assign(A, TypeVarSet, C)).
%-----------------------------------------------------------------------------%
:- pred type_assign_set_type_bindings(type_assign, tsubst, type_assign).
:- mode type_assign_set_type_bindings(in, in, out) is det.
type_assign_set_type_bindings(type_assign(A, B, _), TypeBindings,
type_assign(A, B, TypeBindings)).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
% The next section contains predicates for writing error diagnostics.
%-----------------------------------------------------------------------------%
:- pred report_error_no_clauses(pred_id, pred_info,
module_info, io__state, io__state).
:- mode report_error_no_clauses(in, in, in, di, uo) is det.
report_error_no_clauses(PredId, PredInfo, ModuleInfo) -->
{ pred_info_context(PredInfo, Context) },
prog_out__write_context(Context),
io__write_string("Error: no clauses for "),
hlds_out__write_pred_id(ModuleInfo, PredId),
io__write_string("\n").
%-----------------------------------------------------------------------------%
:- pred report_warning_too_much_overloading(type_info, io__state, io__state).
:- mode report_warning_too_much_overloading(type_info_no_io, di, uo) is det.
report_warning_too_much_overloading(TypeInfo) -->
{ type_info_get_context(TypeInfo, Context) },
write_context_and_pred_id(TypeInfo),
prog_out__write_context(Context),
report_warning(" warning: highly ambiguous overloading.\n"),
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
( { VerboseErrors = yes } ->
prog_out__write_context(Context),
io__write_string(
" This may cause type-checking to be very slow.\n"
),
prog_out__write_context(Context),
io__write_string(
" It may also make your code difficult to understand.\n"
)
;
[]
).
%-----------------------------------------------------------------------------%
:- pred report_error_unif_var_var(type_info, var, var, type_assign_set,
io__state, io__state).
:- mode report_error_unif_var_var(type_info_no_io, in, in, in, di, uo) is det.
report_error_unif_var_var(TypeInfo, X, Y, TypeAssignSet) -->
{ type_info_get_context(TypeInfo, Context) },
{ type_info_get_varset(TypeInfo, VarSet) },
{ type_info_get_unify_context(TypeInfo, UnifyContext) },
write_context_and_pred_id(TypeInfo),
hlds_out__write_unify_context(UnifyContext, Context),
prog_out__write_context(Context),
io__write_string(" type error in unification of variable `"),
mercury_output_var(X, VarSet),
io__write_string("'\n"),
prog_out__write_context(Context),
io__write_string(" and variable `"),
mercury_output_var(Y, VarSet),
io__write_string("'.\n"),
prog_out__write_context(Context),
io__write_string(" `"),
mercury_output_var(X, VarSet),
io__write_string("'"),
write_type_of_var(TypeInfo, TypeAssignSet, X),
io__write_string(",\n"),
prog_out__write_context(Context),
io__write_string(" `"),
mercury_output_var(Y, VarSet),
io__write_string("'"),
write_type_of_var(TypeInfo, TypeAssignSet, Y),
io__write_string(".\n"),
write_type_assign_set_msg(TypeAssignSet, VarSet).
:- pred report_error_functor_type(type_info, var, list(cons_type_info),
const, int,
type_assign_set,
io__state, io__state).
:- mode report_error_functor_type(type_info_no_io, in, in, in, in, in,
di, uo) is det.
report_error_functor_type(TypeInfo, Var, ConsDefnList, Functor, Arity,
TypeAssignSet) -->
{ type_info_get_context(TypeInfo, Context) },
{ type_info_get_varset(TypeInfo, VarSet) },
{ type_info_get_unify_context(TypeInfo, UnifyContext) },
write_context_and_pred_id(TypeInfo),
hlds_out__write_unify_context(UnifyContext, Context),
prog_out__write_context(Context),
io__write_string(" type error in unification of "),
write_argument_name(VarSet, Var),
io__write_string("\n"),
prog_out__write_context(Context),
io__write_string(" and "),
write_functor_name(Functor, Arity),
io__write_string(".\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_argument_name(VarSet, Var),
write_type_of_var(TypeInfo, TypeAssignSet, Var),
io__write_string(",\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_functor_name(Functor, Arity),
write_type_of_functor(Functor, Arity, Context, ConsDefnList),
io__write_string(".\n"),
write_type_assign_set_msg(TypeAssignSet, VarSet).
:- pred report_error_lambda_var(type_info, var, list(var), type_assign_set,
io__state, io__state).
:- mode report_error_lambda_var(type_info_no_io, in, in, in, di, uo) is det.
report_error_lambda_var(TypeInfo, Var, ArgVars, TypeAssignSet) -->
{ type_info_get_context(TypeInfo, Context) },
{ type_info_get_varset(TypeInfo, VarSet) },
{ type_info_get_unify_context(TypeInfo, UnifyContext) },
write_context_and_pred_id(TypeInfo),
hlds_out__write_unify_context(UnifyContext, Context),
prog_out__write_context(Context),
io__write_string(" type error in unification of "),
write_argument_name(VarSet, Var),
io__write_string("\n"),
prog_out__write_context(Context),
io__write_string(" and `lambda ["),
mercury_output_vars(ArgVars, VarSet),
io__write_string("] ...':\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_argument_name(VarSet, Var),
write_type_of_var(TypeInfo, TypeAssignSet, Var),
io__write_string(",\n"),
prog_out__write_context(Context),
io__write_string(" lambda expression has type `pred"),
( { ArgVars = [] } ->
[]
; { ArgVars = [_] } ->
io__write_string("(_)")
; { ArgVars = [_, _] } ->
io__write_string("(_, _)")
; { ArgVars = [_, _, _] } ->
io__write_string("(_, _, _)")
;
io__write_string("(...)")
),
io__write_string("'.\n"),
write_type_assign_set_msg(TypeAssignSet, VarSet).
:- pred report_error_functor_arg_types(type_info, var, list(cons_type_info),
const, list(var),
type_assign_set,
io__state, io__state).
:- mode report_error_functor_arg_types(type_info_no_io, in, in, in, in, in,
di, uo) is det.
report_error_functor_arg_types(TypeInfo, Var, ConsDefnList, Functor, Args,
TypeAssignSet) -->
{ type_info_get_context(TypeInfo, Context) },
{ type_info_get_varset(TypeInfo, VarSet) },
{ type_info_get_unify_context(TypeInfo, UnifyContext) },
{ list__length(Args, Arity) },
write_context_and_pred_id(TypeInfo),
hlds_out__write_unify_context(UnifyContext, Context),
prog_out__write_context(Context),
io__write_string(" in unification of "),
write_argument_name(VarSet, Var),
io__write_string("\n"),
prog_out__write_context(Context),
io__write_string(" and term `"),
hlds_out__write_functor(Functor, Args, VarSet),
io__write_string("':\n"),
prog_out__write_context(Context),
io__write_string(" type error in argument(s) of "),
write_functor_name(Functor, Arity),
io__write_string(".\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_functor_name(Functor, Arity),
write_type_of_functor(Functor, Arity, Context, ConsDefnList),
write_types_of_vars(Args, VarSet, Context, TypeInfo, TypeAssignSet),
write_type_assign_set_msg(TypeAssignSet, VarSet).
:- pred write_types_of_vars(list(var), varset, term__context, type_info,
type_assign_set, io__state, io__state).
:- mode write_types_of_vars(in, in, in, type_info_ui, in, di, uo) is det.
write_types_of_vars([], _, _, _, _) -->
io__write_string(".\n").
write_types_of_vars([Var | Vars], VarSet, Context, TypeInfo, TypeAssignSet) -->
io__write_string(",\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_argument_name(VarSet, Var),
write_type_of_var(TypeInfo, TypeAssignSet, Var),
write_types_of_vars(Vars, VarSet, Context, TypeInfo, TypeAssignSet).
:- pred write_argument_name(varset, var, io__state, io__state).
:- mode write_argument_name(in, in, di, uo) is det.
write_argument_name(VarSet, VarId) -->
( { varset__search_name(VarSet, VarId, _) } ->
io__write_string("variable `"),
mercury_output_var(VarId, VarSet),
io__write_string("'")
;
io__write_string("argument")
).
:- pred write_functor_name(const, int, io__state, io__state).
:- mode write_functor_name(in, in, di, uo) is det.
write_functor_name(Functor, Arity) -->
( { Arity = 0 } ->
io__write_string("constant `"),
term_io__write_constant(Functor)
;
io__write_string("functor `"),
term_io__write_constant(Functor),
io__write_string("/"),
io__write_int(Arity)
),
io__write_string("'").
:- pred write_type_of_var(type_info, type_assign_set, var,
io__state, io__state).
:- mode write_type_of_var(type_info_no_io, in, in, di, uo) is det.
write_type_of_var(_TypeInfo, TypeAssignSet, Var) -->
{ get_type_stuff(TypeAssignSet, Var, TypeStuffList) },
( { TypeStuffList = [SingleTypeStuff] } ->
{ SingleTypeStuff = type_stuff(VType, TVarSet, TBinding) },
io__write_string(" has type `"),
write_type_b(VType, TVarSet, TBinding),
io__write_string("'")
;
io__write_string(" has overloaded type { "),
write_type_stuff_list(TypeStuffList),
io__write_string(" }")
).
:- pred write_type_of_functor(const, int, term__context, list(cons_type_info),
io__state, io__state).
:- mode write_type_of_functor(in, in, in, in, di, uo) is det.
write_type_of_functor(Functor, Arity, Context, ConsDefnList) -->
( { ConsDefnList = [SingleDefn] } ->
io__write_string(" has type "),
( { Arity \= 0 } ->
io__write_string("\n"),
prog_out__write_context(Context),
io__write_string(" `")
;
io__write_string("`")
),
write_cons_type(SingleDefn, Functor, Context),
io__write_string("'")
;
io__write_string(" has overloaded type\n"),
prog_out__write_context(Context),
io__write_string(" { "),
write_cons_type_list(ConsDefnList, Functor, Arity, Context),
io__write_string(" }")
).
:- pred write_cons_type(cons_type_info, const, term__context,
io__state, io__state).
:- mode write_cons_type(in, in, in, di, uo) is det.
write_cons_type(cons_type_info(TVarSet, ConsType, ArgTypes), Functor, Context)
-->
( { ArgTypes \= [] } ->
{ Term = term__functor(Functor, ArgTypes, Context) },
mercury_output_term(Term, TVarSet),
io__write_string(" :: ")
;
[]
),
mercury_output_term(ConsType, TVarSet).
:- pred write_cons_type_list(list(cons_type_info), const, int, term__context,
io__state, io__state).
:- mode write_cons_type_list(in, in, in, in, di, uo) is det.
write_cons_type_list([], _, _, _) --> [].
write_cons_type_list([ConsDefn | ConsDefns], Functor, Arity, Context) -->
write_cons_type(ConsDefn, Functor, Context),
( { ConsDefns = [] } ->
[]
;
( { Arity = 0 } ->
io__write_string(", ")
;
io__write_string(",\n"),
prog_out__write_context(Context),
io__write_string(" ")
),
write_cons_type_list(ConsDefns, Functor, Arity, Context)
).
%-----------------------------------------------------------------------------%
:- pred write_type_assign_set_msg(type_assign_set, tvarset,
io__state, io__state).
:- mode write_type_assign_set_msg(in, in, di, uo) is det.
write_type_assign_set_msg(TypeAssignSet, VarSet) -->
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
( { VerboseErrors = yes } ->
( { TypeAssignSet = [_] } ->
io__write_string("\tThe partial type assignment was:\n")
;
io__write_string(
"\tThe possible partial type assignments were:\n")
),
write_type_assign_set(TypeAssignSet, VarSet)
;
[]
).
:- pred write_args_type_assign_set_msg(args_type_assign_set, tvarset,
io__state, io__state).
:- mode write_args_type_assign_set_msg(in, in, di, uo) is det.
write_args_type_assign_set_msg(ArgTypeAssignSet, VarSet) -->
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
( { VerboseErrors = yes } ->
( { ArgTypeAssignSet = [_] } ->
io__write_string("\tThe partial type assignment was:\n")
;
io__write_string(
"\tThe possible partial type assignments were:\n")
),
write_args_type_assign_set(ArgTypeAssignSet, VarSet)
;
[]
).
%-----------------------------------------------------------------------------%
:- pred write_type_assign_set(type_assign_set, tvarset, io__state, io__state).
:- mode write_type_assign_set(in, in, di, uo) is det.
write_type_assign_set([], _) --> [].
write_type_assign_set([TypeAssign | TypeAssigns], VarSet) -->
io__write_string("\t"),
write_type_assign(TypeAssign, VarSet),
io__write_string("\n"),
write_type_assign_set(TypeAssigns, VarSet).
:- pred write_args_type_assign_set(args_type_assign_set, tvarset,
io__state, io__state).
:- mode write_args_type_assign_set(in, in, di, uo) is det.
write_args_type_assign_set([], _) --> [].
write_args_type_assign_set([TypeAssign - _ArgTypes| TypeAssigns], VarSet) -->
io__write_string("\t"),
write_type_assign(TypeAssign, VarSet),
io__write_string("\n"),
write_args_type_assign_set(TypeAssigns, VarSet).
:- pred write_type_assign(type_assign, tvarset, io__state, io__state).
:- mode write_type_assign(in, in, di, uo) is det.
write_type_assign(TypeAssign, VarSet) -->
{
type_assign_get_var_types(TypeAssign, VarTypes),
type_assign_get_type_bindings(TypeAssign, TypeBindings),
type_assign_get_typevarset(TypeAssign, TypeVarSet),
map__keys(VarTypes, Vars)
},
write_type_assign_2(Vars, VarSet, VarTypes, TypeBindings, TypeVarSet,
no),
io__write_string("\n").
:- pred write_type_assign_2(list(var), varset, map(var, type),
tsubst, tvarset, bool, io__state, io__state).
:- mode write_type_assign_2(in, in, in, in, in, in, di, uo) is det.
write_type_assign_2([], _, _, _, _, FoundOne) -->
( { FoundOne = no } ->
io__write_string("(No variables were assigned a type)")
;
[]
).
write_type_assign_2([Var | Vars], VarSet, VarTypes, TypeBindings, TypeVarSet,
FoundOne) -->
(
{ map__search(VarTypes, Var, Type) }
->
( { FoundOne = yes } ->
io__write_string("\n\t")
;
[]
),
mercury_output_var(Var, VarSet),
io__write_string(" :: "),
write_type_b(Type, TypeVarSet, TypeBindings),
write_type_assign_2(Vars, VarSet, VarTypes, TypeBindings,
TypeVarSet, yes)
;
write_type_assign_2(Vars, VarSet, VarTypes, TypeBindings,
TypeVarSet, FoundOne)
).
% write_type_b writes out a type after applying the type bindings.
:- pred write_type_b(type, tvarset, tsubst, io__state, io__state).
:- mode write_type_b(in, in, in, di, uo) is det.
write_type_b(Type, TypeVarSet, TypeBindings) -->
{ term__apply_rec_substitution(Type, TypeBindings, Type2) },
mercury_output_term(Type2, TypeVarSet).
%-----------------------------------------------------------------------------%
:- pred report_error_var(type_info, var, type, type_assign_set,
io__state, io__state).
:- mode report_error_var(type_info_no_io, in, in, in, di, uo) is det.
report_error_var(TypeInfo, VarId, Type, TypeAssignSet0) -->
{ type_info_get_called_predid(TypeInfo, CalledPredId) },
{ type_info_get_arg_num(TypeInfo, ArgNum) },
{ type_info_get_context(TypeInfo, Context) },
{ type_info_get_unify_context(TypeInfo, UnifyContext) },
{ get_type_stuff(TypeAssignSet0, VarId, TypeStuffList) },
{ type_info_get_varset(TypeInfo, VarSet) },
write_context_and_pred_id(TypeInfo),
write_call_context(Context, CalledPredId, ArgNum, UnifyContext),
prog_out__write_context(Context),
io__write_string(" type error: "),
( { TypeStuffList = [SingleTypeStuff] } ->
write_argument_name(VarSet, VarId),
{ SingleTypeStuff = type_stuff(VType, TVarSet, TBinding) },
io__write_string(" has type `"),
write_type_b(VType, TVarSet, TBinding),
io__write_string("',\n"),
prog_out__write_context(Context),
io__write_string(" expected type was `"),
write_type_b(Type, TVarSet, TBinding),
io__write_string("'.\n")
;
io__write_string("type of "),
write_argument_name(VarSet, VarId),
io__write_string(" does not match its expected type;\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_argument_name(VarSet, VarId),
io__write_string(" has overloaded actual/expected types {\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_var_type_stuff_list(TypeStuffList, Type),
io__write_string("\n"),
prog_out__write_context(Context),
io__write_string(" }.\n")
),
write_type_assign_set_msg(TypeAssignSet0, VarSet).
:- pred report_error_arg_var(type_info, var, args_type_assign_set,
io__state, io__state).
:- mode report_error_arg_var(type_info_no_io, in, in, di, uo) is det.
report_error_arg_var(TypeInfo, VarId, ArgTypeAssignSet0) -->
{ type_info_get_called_predid(TypeInfo, CalledPredId) },
{ type_info_get_arg_num(TypeInfo, ArgNum) },
{ type_info_get_context(TypeInfo, Context) },
{ type_info_get_unify_context(TypeInfo, UnifyContext) },
{ get_arg_type_stuff(ArgTypeAssignSet0, VarId, ArgTypeStuffList) },
{ type_info_get_varset(TypeInfo, VarSet) },
write_context_and_pred_id(TypeInfo),
write_call_context(Context, CalledPredId, ArgNum, UnifyContext),
prog_out__write_context(Context),
io__write_string(" type error: "),
( { ArgTypeStuffList = [SingleArgTypeStuff] } ->
write_argument_name(VarSet, VarId),
{ SingleArgTypeStuff = arg_type_stuff(Type, VType, TVarSet) },
io__write_string(" has type `"),
mercury_output_term(VType, TVarSet),
io__write_string("',\n"),
prog_out__write_context(Context),
io__write_string(" expected type was `"),
mercury_output_term(Type, TVarSet),
io__write_string("'.\n")
;
io__write_string("type of "),
write_argument_name(VarSet, VarId),
io__write_string(" does not match its expected type;\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_argument_name(VarSet, VarId),
io__write_string(" has overloaded actual/expected types {\n"),
prog_out__write_context(Context),
io__write_string(" "),
write_arg_type_stuff_list(ArgTypeStuffList),
io__write_string("\n"),
prog_out__write_context(Context),
io__write_string(" }.\n")
),
write_args_type_assign_set_msg(ArgTypeAssignSet0, VarSet).
:- pred write_type_stuff_list(list(type_stuff), io__state, io__state).
:- mode write_type_stuff_list(in, di, uo) is det.
write_type_stuff_list([]) --> [].
write_type_stuff_list([type_stuff(T, TVarSet, TBinding) | Ts]) -->
write_type_b(T, TVarSet, TBinding),
write_type_stuff_list_2(Ts).
:- pred write_type_stuff_list_2(list(type_stuff), io__state, io__state).
:- mode write_type_stuff_list_2(in, di, uo) is det.
write_type_stuff_list_2([]) --> [].
write_type_stuff_list_2([type_stuff(T, TVarSet, TBinding) | Ts]) -->
io__write_string(", "),
write_type_b(T, TVarSet, TBinding),
write_type_stuff_list_2(Ts).
:- pred write_var_type_stuff_list(list(type_stuff), type, io__state, io__state).
:- mode write_var_type_stuff_list(in, in, di, uo) is det.
write_var_type_stuff_list([], _Type) --> [].
write_var_type_stuff_list([type_stuff(VT, TVarSet, TBinding) | Ts], T) -->
write_type_b(VT, TVarSet, TBinding),
io__write_string("/"),
write_type_b(T, TVarSet, TBinding),
write_var_type_stuff_list_2(Ts, T).
:- pred write_var_type_stuff_list_2(list(type_stuff), type,
io__state, io__state).
:- mode write_var_type_stuff_list_2(in, in, di, uo) is det.
write_var_type_stuff_list_2([], _Type) --> [].
write_var_type_stuff_list_2([type_stuff(VT, TVarSet, TBinding) | Ts], T) -->
io__write_string(", "),
write_type_b(VT, TVarSet, TBinding),
io__write_string("/"),
write_type_b(T, TVarSet, TBinding),
write_type_stuff_list_2(Ts).
:- pred write_arg_type_stuff_list(list(arg_type_stuff), io__state, io__state).
:- mode write_arg_type_stuff_list(in, di, uo) is det.
write_arg_type_stuff_list([]) --> [].
write_arg_type_stuff_list([arg_type_stuff(T, VT, TVarSet) | Ts]) -->
mercury_output_term(VT, TVarSet),
io__write_string("/"),
mercury_output_term(T, TVarSet),
write_arg_type_stuff_list_2(Ts).
:- pred write_arg_type_stuff_list_2(list(arg_type_stuff), io__state, io__state).
:- mode write_arg_type_stuff_list_2(in, di, uo) is det.
write_arg_type_stuff_list_2([]) --> [].
write_arg_type_stuff_list_2([arg_type_stuff(T, VT, TVarSet) | Ts]) -->
io__write_string(", "),
mercury_output_term(VT, TVarSet),
io__write_string("/"),
mercury_output_term(T, TVarSet),
write_arg_type_stuff_list_2(Ts).
%-----------------------------------------------------------------------------%
:- pred report_error_undef_pred(type_info, pred_call_id, io__state, io__state).
:- mode report_error_undef_pred(type_info_no_io, in, di, uo) is det.
report_error_undef_pred(TypeInfo, PredId) -->
write_type_info_context(TypeInfo),
io__write_string(" error: undefined predicate `"),
hlds_out__write_pred_call_id(PredId),
io__write_string("'.\n").
:- pred report_error_pred_num_args(type_info, pred_call_id, list(int),
io__state, io__state).
:- mode report_error_pred_num_args(type_info_no_io, in, in, di, uo) is det.
report_error_pred_num_args(TypeInfo, Name / Arity, Arities) -->
write_type_info_context(TypeInfo),
io__write_string(" error: wrong number of arguments ("),
io__write_int(Arity),
io__write_string("; should be "),
report_error_pred_num_right_args(Arities),
io__write_string(")\n"),
{ type_info_get_context(TypeInfo, Context) },
prog_out__write_context(Context),
io__write_string(" in call to pred `"),
prog_out__write_sym_name(Name),
io__write_string("'.\n").
:- pred report_error_pred_num_right_args(list(int), io__state, io__state).
:- mode report_error_pred_num_right_args(in, di, uo) is det.
report_error_pred_num_right_args([]) --> [].
report_error_pred_num_right_args([Arity | Arities]) -->
io__write_int(Arity),
( { Arities = [] } ->
[]
; { Arities = [_] } ->
io__write_string(" or ")
;
io__write_string(", ")
),
report_error_pred_num_right_args(Arities).
:- pred report_error_undef_cons(type_info, const, int, io__state, io__state).
:- mode report_error_undef_cons(type_info_no_io, in, in, di, uo) is det.
report_error_undef_cons(TypeInfo, Functor, Arity) -->
{ type_info_get_called_predid(TypeInfo, CalledPredId) },
{ type_info_get_arg_num(TypeInfo, ArgNum) },
{ type_info_get_context(TypeInfo, Context) },
{ type_info_get_unify_context(TypeInfo, UnifyContext) },
write_context_and_pred_id(TypeInfo),
write_call_context(Context, CalledPredId, ArgNum, UnifyContext),
prog_out__write_context(Context),
io__write_string(" error: undefined symbol `"),
term_io__write_constant(Functor),
io__write_string("/"),
io__write_int(Arity),
io__write_string("'.\n").
:- pred write_call_context(term__context, pred_call_id, int, unify_context,
io__state, io__state).
:- mode write_call_context(in, in, in, in, di, uo) is det.
write_call_context(Context, PredCallId, ArgNum, UnifyContext) -->
( { ArgNum = 0 } ->
hlds_out__write_unify_context(UnifyContext, Context)
;
prog_out__write_context(Context),
io__write_string(" in argument "),
io__write_int(ArgNum),
io__write_string(" of call to pred `"),
hlds_out__write_pred_call_id(PredCallId),
io__write_string("':\n")
).
%-----------------------------------------------------------------------------%
:- pred write_type_info_context(type_info, io__state, io__state).
:- mode write_type_info_context(type_info_no_io, di, uo) is det.
write_type_info_context(TypeInfo) -->
write_context_and_pred_id(TypeInfo),
{ type_info_get_context(TypeInfo, Context) },
prog_out__write_context(Context).
:- pred write_context_and_pred_id(type_info, io__state, io__state).
:- mode write_context_and_pred_id(type_info_no_io, di, uo) is det.
write_context_and_pred_id(TypeInfo) -->
{ type_info_get_module_info(TypeInfo, ModuleInfo) },
{ type_info_get_context(TypeInfo, Context) },
{ type_info_get_predid(TypeInfo, PredId) },
prog_out__write_context(Context),
io__write_string("In clause for "),
hlds_out__write_pred_id(ModuleInfo, PredId),
io__write_string(":\n").
%-----------------------------------------------------------------------------%
:- pred report_ambiguity_error(type_info, type_assign, type_assign,
io__state, io__state).
:- mode report_ambiguity_error(type_info_no_io, in, in, di, uo) is det.
report_ambiguity_error(TypeInfo, TypeAssign1, TypeAssign2) -->
write_type_info_context(TypeInfo),
io__write_string(" error: ambiguous overloading causes type ambiguity.\n"),
{ type_info_get_context(TypeInfo, Context) },
prog_out__write_context(Context),
io__write_string(" Possible type assignments include:\n"),
{ type_info_get_varset(TypeInfo, VarSet) },
{ type_assign_get_var_types(TypeAssign1, VarTypes1) },
{ map__keys(VarTypes1, Vars1) },
report_ambiguity_error_2(Vars1, VarSet, TypeInfo,
TypeAssign1, TypeAssign2),
globals__io_lookup_bool_option(verbose_errors, VerboseErrors),
( { VerboseErrors = yes } ->
io__write_string("\tYou will need to add an explicit type qualification to resolve the\n"),
io__write_string("\ttype ambiguity.\n"),
io__write_string("\tThe way to add an explicit type qualification\n"),
io__write_string("\tis to insert a call to a dummy predicate whose `:- pred'\n"),
io__write_string("\tdeclaration specifies the appropriate argument types.\n")
;
[]
).
:- pred report_ambiguity_error_2(list(var), varset, type_info,
type_assign, type_assign,
io__state, io__state).
:- mode report_ambiguity_error_2(in, in, type_info_no_io, in, in, di, uo)
is det.
report_ambiguity_error_2([], _VarSet, _, _TypeAssign1, _TypeAssign2) --> [].
report_ambiguity_error_2([V | Vs], VarSet, TypeInfo, TypeAssign1, TypeAssign2)
-->
{ type_assign_get_var_types(TypeAssign1, VarTypes1) },
{ type_assign_get_var_types(TypeAssign2, VarTypes2) },
{ type_assign_get_type_bindings(TypeAssign1, TypeBindings1) },
{ type_assign_get_type_bindings(TypeAssign2, TypeBindings2) },
( {
map__search(VarTypes1, V, Type1),
map__search(VarTypes2, V, Type2),
term__apply_rec_substitution(Type1, TypeBindings1, T1),
term__apply_rec_substitution(Type2, TypeBindings2, T2),
\+ identical_types(T1, T2)
} ->
{ type_info_get_context(TypeInfo, Context) },
prog_out__write_context(Context),
mercury_output_var(V, VarSet),
io__write_string(" :: "),
{ type_assign_get_typevarset(TypeAssign1, TVarSet1) },
mercury_output_term(T1, TVarSet1),
io__write_string(" or "),
{ type_assign_get_typevarset(TypeAssign2, TVarSet2) },
mercury_output_term(T2, TVarSet2),
io__write_string("\n")
;
[]
),
report_ambiguity_error_2(Vs, VarSet, TypeInfo,
TypeAssign1, TypeAssign2).
% Check whether two types are identical ignoring their
% term__contexts, i.e. whether they can be unified without
% binding any type parameters.
:- pred identical_types(type, type).
:- mode identical_types(in, in) is semidet.
identical_types(Type1, Type2) :-
map__init(TypeSubst0),
type_unify(Type1, Type2, [], TypeSubst0, TypeSubst),
TypeSubst = TypeSubst0.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%