mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 21:35:49 +00:00
2468 lines
82 KiB
Mathematica
2468 lines
82 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2007, 2011 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: erlang_rtti_implementation.m.
|
|
% Main author: petdr, wangp.
|
|
% Stability: low.
|
|
%
|
|
% This file is intended to provide the RTTI implementation for the Erlang
|
|
% backend.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module erlang_rtti_implementation.
|
|
:- interface.
|
|
|
|
:- import_module construct.
|
|
:- import_module deconstruct.
|
|
:- import_module list.
|
|
:- import_module type_desc.
|
|
:- import_module univ.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type type_info.
|
|
:- type type_ctor_info.
|
|
:- type type_ctor_info_evaled.
|
|
|
|
:- func get_type_info(T::unused) = (type_info::out) is det.
|
|
|
|
% Check if two values are equal.
|
|
% Note this is not structural equality because a type
|
|
% can have user-defined equality.
|
|
%
|
|
:- pred generic_unify(T::in, T::in) is semidet.
|
|
|
|
:- pred generic_compare(comparison_result::out, T::in, T::in) is det.
|
|
|
|
:- pred compare_type_infos(comparison_result::out,
|
|
type_info::in, type_info::in) is det.
|
|
|
|
:- pred type_ctor_info_and_args(type_info::in, type_ctor_info_evaled::out,
|
|
list(type_info)::out) is det.
|
|
|
|
:- pred type_ctor_desc(type_desc::in, type_ctor_desc::out) is det.
|
|
|
|
:- pred type_ctor_desc_and_args(type_desc::in, type_ctor_desc::out,
|
|
list(type_desc)::out) is det.
|
|
|
|
:- pred make_type_desc(type_ctor_desc::in, list(type_desc)::in,
|
|
type_desc::out) is semidet.
|
|
|
|
:- pred type_ctor_desc_name_and_arity(type_ctor_desc::in,
|
|
string::out, string::out, int::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Implementations for use from deconstruct
|
|
%
|
|
|
|
:- pred functor_number(T::in, functor_number_lex::out, int::out) is semidet.
|
|
|
|
:- pred functor_number_cc(T::in, functor_number_lex::out,
|
|
int::out) is cc_nondet.
|
|
|
|
:- pred deconstruct(T, noncanon_handling, string, int, list(univ)).
|
|
:- mode deconstruct(in, in(do_not_allow), out, out, out) is det.
|
|
:- mode deconstruct(in, in(canonicalize), out, out, out) is det.
|
|
:- mode deconstruct(in, in(include_details_cc), out, out, out) is cc_multi.
|
|
:- mode deconstruct(in, in, out, out, out) is cc_multi.
|
|
|
|
:- pred deconstruct_du(T, noncanon_handling, functor_number_lex,
|
|
int, list(univ)).
|
|
:- mode deconstruct_du(in, in(do_not_allow), out, out, out) is semidet.
|
|
:- mode deconstruct_du(in, in(include_details_cc), out, out, out) is cc_nondet.
|
|
:- mode deconstruct_du(in, in, out, out, out) is cc_nondet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
% Implementation to do with pseudo type descriptions
|
|
|
|
:- pred pseudo_type_ctor_and_args(pseudo_type_desc::in,
|
|
type_ctor_desc::out, list(pseudo_type_desc)::out) is semidet.
|
|
|
|
:- pred is_exist_pseudo_type_desc(pseudo_type_desc::in, int::out) is semidet.
|
|
|
|
:- pred is_univ_pseudo_type_desc(pseudo_type_desc::in, int::out) is semidet.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Implementations for use from construct
|
|
%
|
|
|
|
:- func num_functors(type_desc.type_desc) = int is semidet.
|
|
|
|
:- pred get_functor(type_desc.type_desc::in, functor_number_lex::in,
|
|
string::out, int::out, list(type_desc.type_desc)::out) is semidet.
|
|
|
|
:- pred get_functor_with_names(type_desc.type_desc::in, functor_number_lex::in,
|
|
string::out, int::out, list(type_desc.type_desc)::out, list(string)::out)
|
|
is semidet.
|
|
|
|
:- pred get_functor_ordinal(type_desc.type_desc::in, functor_number_lex::in,
|
|
functor_number_ordinal::out) is semidet.
|
|
|
|
:- pred get_functor_lex(type_desc.type_desc::in, functor_number_ordinal::in,
|
|
functor_number_lex::out) is semidet.
|
|
|
|
:- func construct(type_desc::in, functor_number_lex::in, list(univ)::in)
|
|
= (univ::out) is semidet.
|
|
|
|
:- func construct_tuple_2(list(univ), list(type_desc), int) = univ.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module array.
|
|
:- import_module char.
|
|
:- import_module int.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
:- import_module term_io.
|
|
|
|
% A type_info can be represented in one of three ways
|
|
% For a type with arity 0
|
|
% TypeCtorInfo
|
|
% a type with arity > 0
|
|
% { TypeCtorInfo, TypeInfo0, ..., TypeInfoN }
|
|
% a type with variable arity of size N
|
|
% { TypeCtorInfo, N, TypeInfo0, ..., TypeInfoN }
|
|
%
|
|
% Note that we usually we pass thunks in place of type_ctor_infos
|
|
% themselves.
|
|
%
|
|
:- pragma foreign_type("Erlang", type_info, "").
|
|
:- type type_info
|
|
---> type_info.
|
|
|
|
% In the Erlang RTTI implementation, this is actually a thunk returning a
|
|
% type_ctor_info.
|
|
%
|
|
:- pragma foreign_type("Erlang", type_ctor_info, "").
|
|
:- type type_ctor_info
|
|
---> type_ctor_info.
|
|
|
|
% The actual type_ctor_info, i.e. after evaluating the thunk. For the
|
|
% representation of a type_ctor_info see erl_rtti.type_ctor_data_to_elds.
|
|
%
|
|
:- pragma foreign_type("Erlang", type_ctor_info_evaled, "").
|
|
:- type type_ctor_info_evaled
|
|
---> type_ctor_info_evaled.
|
|
|
|
% The type_ctor_rep needs to be kept up to date with the alternatives
|
|
% given by the function erl_rtti.erlang_type_ctor_rep/1
|
|
%
|
|
:- type erlang_type_ctor_rep
|
|
---> etcr_du
|
|
; etcr_dummy
|
|
; etcr_list
|
|
; etcr_array
|
|
; etcr_eqv
|
|
; etcr_int
|
|
; etcr_float
|
|
; etcr_char
|
|
; etcr_string
|
|
; etcr_void
|
|
; etcr_stable_c_pointer
|
|
; etcr_c_pointer
|
|
; etcr_pred
|
|
; etcr_func
|
|
; etcr_tuple
|
|
; etcr_ref
|
|
; etcr_type_desc
|
|
; etcr_pseudo_type_desc
|
|
; etcr_type_ctor_desc
|
|
; etcr_type_info
|
|
; etcr_type_ctor_info
|
|
; etcr_typeclass_info
|
|
; etcr_base_typeclass_info
|
|
; etcr_foreign
|
|
|
|
% These types shouldn't be needed; they are introduced for library
|
|
% predicates which don't apply on this backend.
|
|
; etcr_hp
|
|
; etcr_subgoal
|
|
; etcr_ticket
|
|
.
|
|
|
|
% Values of type `type_desc' are represented the same way as values of
|
|
% type `type_info'.
|
|
%
|
|
% Values of type `type_ctor_desc' are NOT represented the same way as
|
|
% values of type `type_ctor_info'. The representations *are* in fact
|
|
% identical for fixed arity types, but they differ for higher order and
|
|
% tuple types. In that case they are one of the following:
|
|
%
|
|
% {pred, Arity},
|
|
% {func, Arity},
|
|
% {tuple, Arity}
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_type_info(T) = T ^ type_info.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
generic_unify(X, Y) :-
|
|
TypeInfo = X ^ type_info,
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
( if
|
|
TypeCtorRep = etcr_tuple
|
|
then
|
|
unify_tuple(TypeInfo, X, Y)
|
|
else if
|
|
( TypeCtorRep = etcr_pred ; TypeCtorRep = etcr_func )
|
|
then
|
|
unexpected($module, $pred, "higher order unification not possible")
|
|
else
|
|
Arity = TypeCtorInfo ^ type_ctor_arity,
|
|
UnifyPred = TypeCtorInfo ^ type_ctor_unify_pred,
|
|
( if Arity = 0 then
|
|
semidet_call_3(UnifyPred, X, Y)
|
|
else if Arity = 1 then
|
|
semidet_call_4(UnifyPred,
|
|
TypeInfo ^ type_info_index(1), X, Y)
|
|
else if Arity = 2 then
|
|
semidet_call_5(UnifyPred,
|
|
TypeInfo ^ type_info_index(1),
|
|
TypeInfo ^ type_info_index(2),
|
|
X, Y)
|
|
else if Arity = 3 then
|
|
semidet_call_6(UnifyPred,
|
|
TypeInfo ^ type_info_index(1),
|
|
TypeInfo ^ type_info_index(2),
|
|
TypeInfo ^ type_info_index(3),
|
|
X, Y)
|
|
else if Arity = 4 then
|
|
semidet_call_7(UnifyPred,
|
|
TypeInfo ^ type_info_index(1),
|
|
TypeInfo ^ type_info_index(2),
|
|
TypeInfo ^ type_info_index(3),
|
|
TypeInfo ^ type_info_index(4),
|
|
X, Y)
|
|
else if Arity = 5 then
|
|
semidet_call_8(UnifyPred,
|
|
TypeInfo ^ type_info_index(1),
|
|
TypeInfo ^ type_info_index(2),
|
|
TypeInfo ^ type_info_index(3),
|
|
TypeInfo ^ type_info_index(4),
|
|
TypeInfo ^ type_info_index(5),
|
|
X, Y)
|
|
else
|
|
unexpected($module, $pred, "type arity > 5 not supported")
|
|
)
|
|
).
|
|
|
|
:- pred unify_tuple(type_info::in, T::in, T::in) is semidet.
|
|
|
|
unify_tuple(TypeInfo, X, Y) :-
|
|
Arity = TypeInfo ^ var_arity_type_info_arity,
|
|
unify_tuple_pos(1, Arity, TypeInfo, X, Y).
|
|
|
|
:- pred unify_tuple_pos(int::in, int::in,
|
|
type_info::in, T::in, T::in) is semidet.
|
|
|
|
unify_tuple_pos(Loc, TupleArity, TypeInfo, TermA, TermB) :-
|
|
( if Loc > TupleArity then
|
|
true
|
|
else
|
|
ArgTypeInfo = TypeInfo ^ var_arity_type_info_index(Loc),
|
|
|
|
SubTermA = get_subterm(ArgTypeInfo, TermA, Loc, 0),
|
|
SubTermB = get_subterm(ArgTypeInfo, TermB, Loc, 0),
|
|
|
|
generic_unify(SubTermA, unsafe_cast(SubTermB)),
|
|
|
|
unify_tuple_pos(Loc + 1, TupleArity, TypeInfo, TermA, TermB)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
generic_compare(Res, X, Y) :-
|
|
TypeInfo = X ^ type_info,
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
( if
|
|
TypeCtorRep = etcr_tuple
|
|
then
|
|
compare_tuple(TypeInfo, Res, X, Y)
|
|
else if
|
|
( TypeCtorRep = etcr_pred ; TypeCtorRep = etcr_func )
|
|
then
|
|
unexpected($module, $pred, "higher order comparison not possible")
|
|
else
|
|
Arity = TypeCtorInfo ^ type_ctor_arity,
|
|
ComparePred = TypeCtorInfo ^ type_ctor_compare_pred,
|
|
( if Arity = 0 then
|
|
result_call_4(ComparePred, Res, X, Y)
|
|
else if Arity = 1 then
|
|
result_call_5(ComparePred, Res,
|
|
TypeInfo ^ type_info_index(1), X, Y)
|
|
else if Arity = 2 then
|
|
result_call_6(ComparePred, Res,
|
|
TypeInfo ^ type_info_index(1),
|
|
TypeInfo ^ type_info_index(2),
|
|
X, Y)
|
|
else if Arity = 3 then
|
|
result_call_7(ComparePred, Res,
|
|
TypeInfo ^ type_info_index(1),
|
|
TypeInfo ^ type_info_index(2),
|
|
TypeInfo ^ type_info_index(3),
|
|
X, Y)
|
|
else if Arity = 4 then
|
|
result_call_8(ComparePred, Res,
|
|
TypeInfo ^ type_info_index(1),
|
|
TypeInfo ^ type_info_index(2),
|
|
TypeInfo ^ type_info_index(3),
|
|
TypeInfo ^ type_info_index(4),
|
|
X, Y)
|
|
else if Arity = 5 then
|
|
result_call_9(ComparePred, Res,
|
|
TypeInfo ^ type_info_index(1),
|
|
TypeInfo ^ type_info_index(2),
|
|
TypeInfo ^ type_info_index(3),
|
|
TypeInfo ^ type_info_index(4),
|
|
TypeInfo ^ type_info_index(5),
|
|
X, Y)
|
|
else
|
|
unexpected($module, $pred, "type arity > 5 not supported")
|
|
)
|
|
).
|
|
|
|
:- pred compare_tuple(type_info::in, comparison_result::out, T::in, T::in)
|
|
is det.
|
|
|
|
compare_tuple(TypeInfo, Result, TermA, TermB) :-
|
|
Arity = TypeInfo ^ var_arity_type_info_arity,
|
|
compare_tuple_pos(1, Arity, TypeInfo, Result, TermA, TermB).
|
|
|
|
:- pred compare_tuple_pos(int::in, int::in, type_info::in,
|
|
comparison_result::out, T::in, T::in) is det.
|
|
|
|
compare_tuple_pos(Loc, TupleArity, TypeInfo, Result, TermA, TermB) :-
|
|
( if Loc > TupleArity then
|
|
Result = (=)
|
|
else
|
|
ArgTypeInfo = TypeInfo ^ var_arity_type_info_index(Loc),
|
|
|
|
SubTermA = get_subterm(ArgTypeInfo, TermA, Loc, 0),
|
|
SubTermB = get_subterm(ArgTypeInfo, TermB, Loc, 0),
|
|
|
|
generic_compare(SubResult, SubTermA, unsafe_cast(SubTermB)),
|
|
( if SubResult = (=) then
|
|
compare_tuple_pos(Loc + 1, TupleArity, TypeInfo, Result,
|
|
TermA, TermB)
|
|
else
|
|
Result = SubResult
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
compare_type_infos(Res, TypeInfoA, TypeInfoB) :-
|
|
TA = collapse_equivalences(TypeInfoA),
|
|
TB = collapse_equivalences(TypeInfoB),
|
|
|
|
TCA = TA ^ type_ctor_info_evaled,
|
|
TCB = TB ^ type_ctor_info_evaled,
|
|
|
|
compare(ModuleRes,
|
|
TCA ^ type_ctor_module_name, TCB ^ type_ctor_module_name),
|
|
(
|
|
ModuleRes = (=),
|
|
compare(NameRes, TCA ^ type_ctor_type_name, TCB ^ type_ctor_type_name),
|
|
(
|
|
NameRes = (=),
|
|
( if type_ctor_is_variable_arity(TCA) then
|
|
ArityA = TA ^ var_arity_type_info_arity,
|
|
ArityB = TB ^ var_arity_type_info_arity,
|
|
compare(ArityRes, ArityA, ArityB),
|
|
(
|
|
ArityRes = (=),
|
|
compare_var_arity_typeinfos(1, ArityA, Res, TA, TB)
|
|
;
|
|
( ArityRes = (<)
|
|
; ArityRes = (>)
|
|
),
|
|
Res = ArityRes
|
|
)
|
|
else
|
|
ArityA = TCA ^ type_ctor_arity,
|
|
ArityB = TCA ^ type_ctor_arity,
|
|
compare(ArityRes, ArityA, ArityB),
|
|
(
|
|
ArityRes = (=),
|
|
compare_sub_typeinfos(1, ArityA, Res, TA, TB)
|
|
;
|
|
( ArityRes = (<)
|
|
; ArityRes = (>)
|
|
),
|
|
Res = ArityRes
|
|
)
|
|
)
|
|
;
|
|
( NameRes = (<)
|
|
; NameRes = (>)
|
|
),
|
|
Res = NameRes
|
|
)
|
|
;
|
|
( ModuleRes = (<)
|
|
; ModuleRes = (>)
|
|
),
|
|
Res = ModuleRes
|
|
).
|
|
|
|
:- pred compare_sub_typeinfos(int::in, int::in,
|
|
comparison_result::out, type_info::in, type_info::in) is det.
|
|
|
|
compare_sub_typeinfos(Loc, Arity, Result, TypeInfoA, TypeInfoB) :-
|
|
( if Loc > Arity then
|
|
Result = (=)
|
|
else
|
|
SubTypeInfoA = TypeInfoA ^ type_info_index(Loc),
|
|
SubTypeInfoB = TypeInfoB ^ type_info_index(Loc),
|
|
|
|
compare_type_infos(SubResult, SubTypeInfoA, SubTypeInfoB),
|
|
(
|
|
SubResult = (=),
|
|
compare_sub_typeinfos(Loc + 1, Arity, Result,
|
|
TypeInfoA, TypeInfoB)
|
|
;
|
|
( SubResult = (<)
|
|
; SubResult = (>)
|
|
),
|
|
Result = SubResult
|
|
)
|
|
).
|
|
|
|
:- pred compare_var_arity_typeinfos(int::in, int::in,
|
|
comparison_result::out, type_info::in, type_info::in) is det.
|
|
|
|
compare_var_arity_typeinfos(Loc, Arity, Result, TypeInfoA, TypeInfoB) :-
|
|
( if Loc > Arity then
|
|
Result = (=)
|
|
else
|
|
SubTypeInfoA = TypeInfoA ^ var_arity_type_info_index(Loc),
|
|
SubTypeInfoB = TypeInfoB ^ var_arity_type_info_index(Loc),
|
|
|
|
compare_type_infos(SubResult, SubTypeInfoA, SubTypeInfoB),
|
|
(
|
|
SubResult = (=),
|
|
compare_var_arity_typeinfos(Loc + 1, Arity, Result,
|
|
TypeInfoA, TypeInfoB)
|
|
;
|
|
( SubResult = (<)
|
|
; SubResult = (>)
|
|
),
|
|
Result = SubResult
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
type_ctor_info_and_args(TypeInfo0, TypeCtorInfo, Args) :-
|
|
TypeInfo = collapse_equivalences(TypeInfo0),
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
( if type_ctor_is_variable_arity(TypeCtorInfo) then
|
|
Args = get_var_arity_arg_type_infos(TypeInfo)
|
|
else
|
|
Args = get_fixed_arity_arg_type_infos(TypeInfo)
|
|
).
|
|
|
|
:- pred type_ctor_is_variable_arity(type_ctor_info_evaled::in) is semidet.
|
|
|
|
type_ctor_is_variable_arity(TypeCtorInfo) :-
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
( TypeCtorRep = etcr_tuple
|
|
; TypeCtorRep = etcr_pred
|
|
; TypeCtorRep = etcr_func
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
type_ctor_desc(TypeDesc, TypeCtorDesc) :-
|
|
type_ctor_desc_and_args(TypeDesc, TypeCtorDesc, _Args).
|
|
|
|
type_ctor_desc_and_args(TypeDesc, TypeCtorDesc, ArgsDescs) :-
|
|
TypeInfo0 = type_info_from_type_desc(TypeDesc),
|
|
TypeInfo = collapse_equivalences(TypeInfo0),
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
% Handle variable arity types.
|
|
( if TypeCtorRep = etcr_pred then
|
|
Arity = TypeInfo ^ var_arity_type_info_arity,
|
|
TypeCtorDesc = make_pred_type_ctor_desc(Arity),
|
|
ArgInfos = get_var_arity_arg_type_infos(TypeInfo)
|
|
|
|
else if TypeCtorRep = etcr_func then
|
|
Arity = TypeInfo ^ var_arity_type_info_arity,
|
|
TypeCtorDesc = make_func_type_ctor_desc(Arity),
|
|
ArgInfos = get_var_arity_arg_type_infos(TypeInfo)
|
|
|
|
else if TypeCtorRep = etcr_tuple then
|
|
Arity = TypeInfo ^ var_arity_type_info_arity,
|
|
TypeCtorDesc = make_tuple_type_ctor_desc(Arity),
|
|
ArgInfos = get_var_arity_arg_type_infos(TypeInfo)
|
|
else
|
|
% Handle fixed arity types.
|
|
TypeCtorDesc = make_fixed_arity_type_ctor_desc(TypeCtorInfo),
|
|
ArgInfos = get_fixed_arity_arg_type_infos(TypeInfo)
|
|
),
|
|
ArgsDescs = type_descs_from_type_infos(ArgInfos).
|
|
|
|
:- func make_pred_type_ctor_desc(int) = type_ctor_desc.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
make_pred_type_ctor_desc(Arity::in) = (TypeCtorDesc::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
TypeCtorDesc = {pred, Arity}
|
|
").
|
|
|
|
make_pred_type_ctor_desc(_) = _ :-
|
|
private_builtin.sorry("make_pred_type_ctor_desc").
|
|
|
|
:- func make_func_type_ctor_desc(int) = type_ctor_desc.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
make_func_type_ctor_desc(Arity::in) = (TypeCtorDesc::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
TypeCtorDesc = {func, Arity}
|
|
").
|
|
|
|
make_func_type_ctor_desc(_) = _ :-
|
|
private_builtin.sorry("make_func_type_ctor_desc").
|
|
|
|
:- func make_tuple_type_ctor_desc(int) = type_ctor_desc.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
make_tuple_type_ctor_desc(Arity::in) = (TypeCtorDesc::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
TypeCtorDesc = {tuple, Arity}
|
|
").
|
|
|
|
make_tuple_type_ctor_desc(_) = _ :-
|
|
private_builtin.sorry("make_tuple_type_ctor_desc").
|
|
|
|
:- func make_fixed_arity_type_ctor_desc(type_ctor_info_evaled)
|
|
= type_ctor_desc.
|
|
|
|
make_fixed_arity_type_ctor_desc(TypeCtorInfo) = TypeCtorDesc :-
|
|
% Fixed arity types have the same representations.
|
|
TypeCtorDesc = unsafe_cast(TypeCtorInfo).
|
|
|
|
:- func type_info_from_type_desc(type_desc) = type_info.
|
|
|
|
type_info_from_type_desc(TypeDesc) = TypeInfo :-
|
|
% They have the same representation.
|
|
TypeInfo = unsafe_cast(TypeDesc).
|
|
|
|
:- func type_descs_from_type_infos(list(type_info)) = list(type_desc).
|
|
|
|
type_descs_from_type_infos(TypeInfos) = TypeDescs :-
|
|
% They have the same representation.
|
|
TypeDescs = unsafe_cast(TypeInfos).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
make_type_desc(TypeCtorDesc::in, ArgTypeDescs::in, TypeDesc::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
MakeVarArityTypeDesc =
|
|
(fun(TypeCtorInfo, Arity, ArgTypeInfos) ->
|
|
case Arity =:= length(ArgTypeInfos) of
|
|
true ->
|
|
TypeInfo =
|
|
list_to_tuple([TypeCtorInfo, Arity | ArgTypeDescs]),
|
|
{true, TypeInfo};
|
|
false ->
|
|
{false, null}
|
|
end
|
|
end),
|
|
|
|
case TypeCtorDesc of
|
|
% Handle the variable arity types.
|
|
{pred, Arity} ->
|
|
TCI = fun mercury__builtin:builtin__type_ctor_info_pred_0/0,
|
|
{SUCCESS_INDICATOR, TypeDesc} = MakeVarArityTypeDesc(TCI, Arity,
|
|
ArgTypeDescs);
|
|
|
|
{func, Arity} ->
|
|
TCI = fun mercury__builtin:builtin__type_ctor_info_func_0/0,
|
|
{SUCCESS_INDICATOR, TypeDesc} = MakeVarArityTypeDesc(TCI, Arity,
|
|
ArgTypeDescs);
|
|
|
|
{tuple, Arity} ->
|
|
TCI = fun mercury__builtin:builtin__type_ctor_info_tuple_0/0,
|
|
{SUCCESS_INDICATOR, TypeDesc} = MakeVarArityTypeDesc(TCI, Arity,
|
|
ArgTypeDescs);
|
|
|
|
% Handle fixed arity types.
|
|
TypeCtorInfo ->
|
|
ArgTypeInfos = ArgTypeDescs,
|
|
case
|
|
mercury__erlang_rtti_implementation:
|
|
'ML_make_fixed_arity_type_info'(TypeCtorInfo, ArgTypeInfos)
|
|
of
|
|
{TypeInfo} ->
|
|
SUCCESS_INDICATOR = true,
|
|
% type_desc and type_info have same representation.
|
|
TypeDesc = TypeInfo;
|
|
fail ->
|
|
SUCCESS_INDICATOR = false,
|
|
TypeDesc = null
|
|
end
|
|
end
|
|
").
|
|
|
|
make_type_desc(_, _, _) :-
|
|
private_builtin.sorry("make_type_desc/3").
|
|
|
|
:- pred make_fixed_arity_type_info(type_ctor_info_evaled::in,
|
|
list(type_info)::in, type_info::out) is semidet.
|
|
|
|
:- pragma foreign_export("Erlang", make_fixed_arity_type_info(in, in, out),
|
|
"ML_make_fixed_arity_type_info").
|
|
|
|
make_fixed_arity_type_info(TypeCtorInfo, ArgTypeInfos, TypeInfo) :-
|
|
TypeCtorInfo ^ type_ctor_arity = list.length(ArgTypeInfos),
|
|
TypeInfo = create_type_info(TypeCtorInfo, ArgTypeInfos).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_desc_name_and_arity(TypeCtorDesc::in, ModuleName::out, Name::out,
|
|
Arity::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
case TypeCtorDesc of
|
|
{pred, Arity} ->
|
|
ModuleName = <<""builtin"">>,
|
|
Name = <<""pred"">>,
|
|
Arity = Arity;
|
|
|
|
{func, Arity} ->
|
|
ModuleName = <<""builtin"">>,
|
|
Name = <<""func"">>,
|
|
Arity = Arity;
|
|
|
|
{tuple, Arity} ->
|
|
ModuleName = <<""builtin"">>,
|
|
Name = <<""{}"">>,
|
|
Arity = Arity;
|
|
|
|
TypeCtorInfo ->
|
|
{ModuleName, Name, Arity} =
|
|
mercury__erlang_rtti_implementation:
|
|
'ML_type_ctor_info_name_and_arity'(TypeCtorInfo)
|
|
end
|
|
").
|
|
|
|
type_ctor_desc_name_and_arity(_, _, _, _) :-
|
|
private_builtin.sorry("type_ctor_desc_name_and_arity/4").
|
|
|
|
:- pred type_ctor_info_name_and_arity(type_ctor_info_evaled::in,
|
|
string::out, string::out, int::out) is det.
|
|
|
|
:- pragma foreign_export("Erlang",
|
|
type_ctor_info_name_and_arity(in, out, out, out),
|
|
"ML_type_ctor_info_name_and_arity").
|
|
|
|
type_ctor_info_name_and_arity(TypeCtorInfo, ModuleName, Name, Arity) :-
|
|
ModuleName = TypeCtorInfo ^ type_ctor_module_name,
|
|
Name = TypeCtorInfo ^ type_ctor_type_name,
|
|
Arity = TypeCtorInfo ^ type_ctor_arity.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
functor_number(Term, FunctorNumber, Arity) :-
|
|
TypeInfo = Term ^ type_info,
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
is_du_type(TypeCtorRep),
|
|
NonCanon = do_not_allow,
|
|
deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
|
|
_Functor, FunctorNumber, Arity, _Arguments).
|
|
|
|
functor_number_cc(Term, FunctorNumber, Arity) :-
|
|
TypeInfo = Term ^ type_info,
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
is_du_type(TypeCtorRep),
|
|
NonCanon = canonicalize,
|
|
deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
|
|
_Functor, FunctorNumber, Arity0, _Arguments),
|
|
% XXX force cc_multi as required by the interface for functor_number_cc.
|
|
% It seems wrong since deconstruct(canonicalize) is det.
|
|
( Arity = Arity0
|
|
; Arity = Arity0
|
|
).
|
|
|
|
deconstruct(Term, NonCanon, Functor, Arity, Arguments) :-
|
|
TypeInfo = Term ^ type_info,
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
|
|
Functor, _FunctorNumber, Arity, Arguments).
|
|
|
|
deconstruct_du(Term, NonCanon, FunctorNumber, Arity, Arguments) :-
|
|
TypeInfo = Term ^ type_info,
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
is_du_type(TypeCtorRep),
|
|
deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
|
|
_Functor, FunctorNumber, Arity, Arguments).
|
|
|
|
:- pred is_du_type(erlang_type_ctor_rep::in) is semidet.
|
|
|
|
is_du_type(etcr_du).
|
|
is_du_type(etcr_dummy).
|
|
is_du_type(etcr_list).
|
|
is_du_type(etcr_tuple).
|
|
|
|
:- pred deconstruct_2(T, type_info, type_ctor_info_evaled,
|
|
erlang_type_ctor_rep, noncanon_handling, string, int, int, list(univ)).
|
|
:- mode deconstruct_2(in, in, in, in, in(do_not_allow), out, out, out, out)
|
|
is det.
|
|
:- mode deconstruct_2(in, in, in, in, in(canonicalize), out, out, out, out)
|
|
is det.
|
|
:- mode deconstruct_2(in, in, in, in,
|
|
in(include_details_cc), out, out, out, out) is cc_multi.
|
|
:- mode deconstruct_2(in, in, in, in, in, out, out, out, out) is cc_multi.
|
|
|
|
deconstruct_2(Term, TypeInfo, TypeCtorInfo, TypeCtorRep, NonCanon,
|
|
Functor, FunctorNumber, Arity, Arguments) :-
|
|
(
|
|
TypeCtorRep = etcr_du,
|
|
FunctorReps = TypeCtorInfo ^ type_ctor_functors,
|
|
matching_du_functor(FunctorReps, Term, FunctorRep),
|
|
Functor = string.from_char_list(FunctorRep ^ edu_name),
|
|
FunctorNumber = FunctorRep ^ edu_lex,
|
|
Arity = FunctorRep ^ edu_orig_arity,
|
|
Arguments = list.map(
|
|
get_du_functor_arg(TypeInfo, FunctorRep, Term), 1 .. Arity)
|
|
;
|
|
TypeCtorRep = etcr_dummy,
|
|
Functor = TypeCtorInfo ^ type_ctor_dummy_functor_name,
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
TypeCtorRep = etcr_list,
|
|
ArgTypeInfo = TypeInfo ^ type_info_index(1),
|
|
( if is_non_empty_list(TypeInfo, ArgTypeInfo, Term, H, T) then
|
|
Functor = "[|]",
|
|
FunctorNumber = 1,
|
|
Arity = 2,
|
|
Arguments = [univ(H), univ(T)]
|
|
else
|
|
Functor = "[]",
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
)
|
|
;
|
|
TypeCtorRep = etcr_array,
|
|
|
|
% Constrain the T in array(T) to the correct element type.
|
|
type_ctor_and_args(type_of(Term), _, Args),
|
|
( if Args = [ElemType] then
|
|
has_type(Elem, ElemType),
|
|
same_array_elem_type(Array, Elem)
|
|
else
|
|
unexpected($module, $pred,
|
|
"An array which doesn't have a type_ctor arg")
|
|
),
|
|
|
|
det_dynamic_cast(Term, Array),
|
|
|
|
Functor = "<<array>>",
|
|
FunctorNumber = 0,
|
|
Arity = array.size(Array),
|
|
Arguments = array.foldr(
|
|
(func(Elem, List) = [univ(Elem) | List]),
|
|
Array, [])
|
|
;
|
|
TypeCtorRep = etcr_eqv,
|
|
EqvTypeInfo = collapse_equivalences(TypeInfo),
|
|
EqvTypeCtorInfo = EqvTypeInfo ^ type_ctor_info_evaled,
|
|
EqvTypeCtorRep = EqvTypeCtorInfo ^ type_ctor_rep,
|
|
deconstruct_2(Term, EqvTypeInfo, EqvTypeCtorInfo, EqvTypeCtorRep,
|
|
NonCanon, Functor, FunctorNumber, Arity, Arguments)
|
|
;
|
|
TypeCtorRep = etcr_tuple,
|
|
Arity = TypeInfo ^ var_arity_type_info_arity,
|
|
Functor = "{}",
|
|
FunctorNumber = 0,
|
|
Arguments = list.map(get_tuple_arg(TypeInfo, Term), 1 .. Arity)
|
|
;
|
|
TypeCtorRep = etcr_int,
|
|
det_dynamic_cast(Term, Int),
|
|
Functor = string.int_to_string(Int),
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
TypeCtorRep = etcr_float,
|
|
det_dynamic_cast(Term, Float),
|
|
Functor = float_to_string(Float),
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
TypeCtorRep = etcr_char,
|
|
det_dynamic_cast(Term, Char),
|
|
Functor = term_io.quoted_char(Char),
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
TypeCtorRep = etcr_string,
|
|
det_dynamic_cast(Term, String),
|
|
Functor = "\"" ++ String ++ "\"",
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
% There is no way to create values of type `void', so this
|
|
% should never happen.
|
|
TypeCtorRep = etcr_void,
|
|
unexpected($module, $pred, "cannot deconstruct void types")
|
|
;
|
|
TypeCtorRep = etcr_stable_c_pointer,
|
|
det_dynamic_cast(Term, CPtr),
|
|
Functor = "stable_" ++ string.c_pointer_to_string(CPtr),
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
TypeCtorRep = etcr_c_pointer,
|
|
det_dynamic_cast(Term, CPtr),
|
|
Functor = string.c_pointer_to_string(CPtr),
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
( TypeCtorRep = etcr_pred,
|
|
Name = "<<predicate>>"
|
|
; TypeCtorRep = etcr_func,
|
|
Name = "<<function>>"
|
|
; TypeCtorRep = etcr_ref,
|
|
Name = "<<reference>>"
|
|
; TypeCtorRep = etcr_type_desc,
|
|
Name = "<<typedesc>>"
|
|
; TypeCtorRep = etcr_pseudo_type_desc,
|
|
Name = "<<pseudotypedesc>>"
|
|
; TypeCtorRep = etcr_type_ctor_desc,
|
|
Name = "<<typectordesc>>"
|
|
; TypeCtorRep = etcr_type_info,
|
|
Name = "<<typeinfo>>"
|
|
; TypeCtorRep = etcr_type_ctor_info,
|
|
Name = "<<typectorinfo>>"
|
|
; TypeCtorRep = etcr_typeclass_info,
|
|
Name = "<<typeclassinfo>>"
|
|
; TypeCtorRep = etcr_base_typeclass_info,
|
|
Name = "<<basetypeclassinfo>>"
|
|
),
|
|
(
|
|
NonCanon = do_not_allow,
|
|
unexpected($module, $pred,
|
|
"attempt to deconstruct noncanonical term")
|
|
;
|
|
NonCanon = canonicalize,
|
|
Functor = Name,
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
% XXX this needs to be fixed
|
|
NonCanon = include_details_cc,
|
|
Functor = Name,
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
)
|
|
;
|
|
TypeCtorRep = etcr_foreign,
|
|
Functor = "<<foreign>>",
|
|
FunctorNumber = 0,
|
|
Arity = 0,
|
|
Arguments = []
|
|
;
|
|
|
|
% These types shouldn't be needed; they are introduced for library
|
|
% predicates which don't apply on this backend.
|
|
( TypeCtorRep = etcr_hp
|
|
; TypeCtorRep = etcr_subgoal
|
|
; TypeCtorRep = etcr_ticket
|
|
),
|
|
unexpected($module, $pred,
|
|
"should never occur: " ++ string(TypeCtorRep))
|
|
).
|
|
|
|
% matching_du_functor(FunctorReps, Term, FunctorRep)
|
|
%
|
|
% Finds the erlang_du_functor in the list Functors which describes
|
|
% the given Term.
|
|
%
|
|
:- pred matching_du_functor(list(erlang_du_functor)::in, T::in,
|
|
erlang_du_functor::out) is det.
|
|
|
|
matching_du_functor([], _, _) :-
|
|
unexpected($module, $pred, "empty list").
|
|
matching_du_functor([F | Fs], T, Functor) :-
|
|
( if matches_du_functor(T, F) then
|
|
Functor = F
|
|
else
|
|
matching_du_functor(Fs, T, Functor)
|
|
).
|
|
|
|
% A functor matches a term, if the first argument of the term
|
|
% is the same erlang atom as the recorded in the edu_rep field,
|
|
% and the size of the term matches the calculated size of term.
|
|
%
|
|
% Note we have to do this second step because a functor is distinguished
|
|
% by both it's name and arity.
|
|
%
|
|
% Note it is possible for this code to do the wrong thing, see the comment
|
|
% at the top of erl_unify_gen.m.
|
|
%
|
|
:- pred matches_du_functor(T::in, erlang_du_functor::in) is semidet.
|
|
|
|
matches_du_functor(Term, Functor) :-
|
|
check_functor(Term, Functor ^ edu_rep, Size),
|
|
Functor ^ edu_orig_arity + 1 + extra_args(Functor) = Size.
|
|
|
|
:- pred check_functor(T::in, erlang_atom::in, int::out) is semidet.
|
|
:- pragma foreign_proc("Erlang",
|
|
check_functor(Term::in, Atom::in, Size::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
case Atom of
|
|
% This case must come before the next to handle existential types using
|
|
% the '[|]' constructor. In that case the Erlang term will be a tuple
|
|
% and not a list.
|
|
_ when is_tuple(Term) ->
|
|
Functor = element(1, Term),
|
|
Size = size(Term),
|
|
SUCCESS_INDICATOR = Functor =:= Atom;
|
|
|
|
'[|]' ->
|
|
case Term of
|
|
[_ | _] ->
|
|
SUCCESS_INDICATOR = true;
|
|
_ ->
|
|
SUCCESS_INDICATOR = false
|
|
end,
|
|
Size = 3;
|
|
|
|
'[]' ->
|
|
SUCCESS_INDICATOR = Term =:= [],
|
|
Size = 1
|
|
end
|
|
").
|
|
check_functor(_, _, 0) :-
|
|
semidet_unimplemented("check_functor/3").
|
|
|
|
:- some [H, T] pred is_non_empty_list(type_info::in, type_info::in,
|
|
L::in, H::out, T::out) is semidet.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
is_non_empty_list(ListTI::in, ElemTI::in, L::in, H::out, T::out),
|
|
[promise_pure, will_not_call_mercury, thread_safe],
|
|
"
|
|
% TypeInfo_for_L
|
|
TypeInfo_for_H = ElemTI,
|
|
TypeInfo_for_T = ListTI,
|
|
case L of
|
|
[] ->
|
|
SUCCESS_INDICATOR = false,
|
|
H = void,
|
|
T = void;
|
|
[Head | Tail] ->
|
|
SUCCESS_INDICATOR = true,
|
|
H = Head,
|
|
T = Tail
|
|
end
|
|
").
|
|
|
|
is_non_empty_list(_, _, _, "dummy value", "dummy value") :-
|
|
semidet_unimplemented("is_non_empty_list/5").
|
|
|
|
%
|
|
% Calculate the number of type_info and type_class_infos which
|
|
% have been introduced due to existentially quantified type
|
|
% variables on the given functor.
|
|
%
|
|
:- func extra_args(erlang_du_functor) = int.
|
|
|
|
extra_args(Functor) = ExtraArgs :-
|
|
MaybeExist = Functor ^ edu_exist_info,
|
|
(
|
|
MaybeExist = yes(ExistInfo),
|
|
% XXX We should record the number of typeclass_constraints
|
|
% in the exist_info.
|
|
ExtraArgs = ExistInfo ^ exist_num_plain_typeinfos +
|
|
list.length(ExistInfo ^ exist_typeclass_constraints)
|
|
;
|
|
MaybeExist = no,
|
|
ExtraArgs = 0
|
|
).
|
|
|
|
% get_du_functor_arg(TypeInfo, Functor, Term, N)
|
|
%
|
|
% Returns a univ which represents the N'th argument of the term, Term,
|
|
% which is described by the erlang_du_functor Functor, and the type_info
|
|
% TypeInfo.
|
|
%
|
|
:- func get_du_functor_arg(type_info, erlang_du_functor, T, int) = univ.
|
|
|
|
get_du_functor_arg(TypeInfo, Functor, Term, Loc) = Univ :-
|
|
ArgInfo = list.det_index1(Functor ^ edu_arg_infos, Loc),
|
|
|
|
MaybePTI = ArgInfo ^ du_arg_type,
|
|
Info = yes({TypeInfo, yes({Functor, Term})}),
|
|
ArgTypeInfo = concrete_type_info(Info, MaybePTI),
|
|
|
|
SubTerm = get_subterm(ArgTypeInfo, Term, Loc, extra_args(Functor) + 1),
|
|
Univ = univ(SubTerm).
|
|
|
|
% get_tuple_arg(TypeInfo, Tuple, N)
|
|
%
|
|
% Get the N'th argument as a univ from the tuple described by the
|
|
% type_info.
|
|
%
|
|
:- func get_tuple_arg(type_info, U, int) = univ.
|
|
|
|
get_tuple_arg(TypeInfo, Term, Loc) = Univ :-
|
|
ArgTypeInfo = TypeInfo ^ var_arity_type_info_index(Loc),
|
|
SubTerm = get_subterm(ArgTypeInfo, Term, Loc, 0),
|
|
Univ = univ(SubTerm).
|
|
|
|
:- pred same_array_elem_type(array(T)::unused, T::unused) is det.
|
|
|
|
same_array_elem_type(_, _).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func collapse_equivalences(type_info) = type_info.
|
|
|
|
collapse_equivalences(TypeInfo0) = TypeInfo :-
|
|
TypeCtorInfo0 = TypeInfo0 ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo0 ^ type_ctor_rep,
|
|
( if TypeCtorRep = etcr_eqv then
|
|
PtiInfo = no : pti_info(int),
|
|
TiInfo = yes({TypeInfo0, PtiInfo}),
|
|
EqvType = TypeCtorInfo0 ^ type_ctor_eqv_type,
|
|
TypeInfo1 = concrete_type_info(TiInfo, EqvType),
|
|
TypeInfo = collapse_equivalences(TypeInfo1)
|
|
else
|
|
TypeInfo = TypeInfo0
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
pseudo_type_ctor_and_args(PseudoTypeDesc, TypeCtorDesc, Args) :-
|
|
% XXX Still need to handle equivalence types.
|
|
EvalPTI = pseudo_type_desc_to_pseudo_type_info(PseudoTypeDesc),
|
|
EvalPTI = pseudo_type_info(PTI),
|
|
|
|
TI = unsafe_cast(PTI),
|
|
|
|
TypeCtorInfo = TI ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
|
|
( if TypeCtorRep = etcr_pred then
|
|
Arity = TI ^ var_arity_type_info_arity,
|
|
TypeCtorDesc = make_pred_type_ctor_desc(Arity),
|
|
ArgInfos = get_var_arity_arg_type_infos(TI)
|
|
else if TypeCtorRep = etcr_func then
|
|
Arity = TI ^ var_arity_type_info_arity,
|
|
TypeCtorDesc = make_func_type_ctor_desc(Arity),
|
|
ArgInfos = get_var_arity_arg_type_infos(TI)
|
|
else if TypeCtorRep = etcr_tuple then
|
|
Arity = TI ^ var_arity_type_info_arity,
|
|
TypeCtorDesc = make_tuple_type_ctor_desc(Arity),
|
|
ArgInfos = get_var_arity_arg_type_infos(TI)
|
|
else
|
|
% Handle fixed arity types.
|
|
TypeCtorDesc = make_fixed_arity_type_ctor_desc(TypeCtorInfo),
|
|
( if TypeCtorInfo ^ type_ctor_arity = 0 then
|
|
ArgInfos = []
|
|
else
|
|
ArgInfos = get_fixed_arity_arg_type_infos(TI)
|
|
)
|
|
),
|
|
Args = pseudo_type_descs_from_type_infos(ArgInfos).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
is_exist_pseudo_type_desc(PseudoTypeDesc, Int) :-
|
|
EvalPTI = pseudo_type_desc_to_pseudo_type_info(PseudoTypeDesc),
|
|
EvalPTI = existential_type_info(Int).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
is_univ_pseudo_type_desc(PseudoTypeDesc, Int) :-
|
|
EvalPTI = pseudo_type_desc_to_pseudo_type_info(PseudoTypeDesc),
|
|
EvalPTI = universal_type_info(Int).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func pseudo_type_desc_to_pseudo_type_info(
|
|
pseudo_type_desc) = evaluated_pseudo_type_info_thunk.
|
|
|
|
pseudo_type_desc_to_pseudo_type_info(PseudoTypeDesc) =
|
|
eval_pseudo_type_info_thunk(unsafe_cast(PseudoTypeDesc)).
|
|
|
|
:- func type_ctor_info_from_pseudo_type_info(pseudo_type_info) =
|
|
type_ctor_info_evaled.
|
|
|
|
type_ctor_info_from_pseudo_type_info(PTI) =
|
|
unsafe_cast(PTI) ^ type_ctor_info_evaled.
|
|
|
|
:- func pseudo_type_descs_from_type_infos(list(type_info)) =
|
|
list(pseudo_type_desc).
|
|
|
|
pseudo_type_descs_from_type_infos(TypeInfos) = PseudoTypeDescs :-
|
|
% They have the same representation.
|
|
PseudoTypeDescs = unsafe_cast(TypeInfos).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
num_functors(TypeDesc) = NumFunctors :-
|
|
TypeInfo = type_info_from_type_desc(TypeDesc),
|
|
num_functors(TypeInfo, yes(NumFunctors)).
|
|
|
|
:- pred num_functors(type_info::in, maybe(int)::out) is det.
|
|
|
|
num_functors(TypeInfo, MaybeNumFunctors) :-
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
(
|
|
TypeCtorRep = etcr_du,
|
|
FunctorReps = TypeCtorInfo ^ type_ctor_functors,
|
|
MaybeNumFunctors = yes(list.length(FunctorReps))
|
|
;
|
|
( TypeCtorRep = etcr_dummy
|
|
; TypeCtorRep = etcr_tuple
|
|
),
|
|
MaybeNumFunctors = yes(1)
|
|
;
|
|
TypeCtorRep = etcr_list,
|
|
MaybeNumFunctors = yes(2)
|
|
;
|
|
TypeCtorRep = etcr_eqv,
|
|
EqvTypeInfo = collapse_equivalences(TypeInfo),
|
|
num_functors(EqvTypeInfo, MaybeNumFunctors)
|
|
;
|
|
( TypeCtorRep = etcr_array
|
|
; TypeCtorRep = etcr_int
|
|
; TypeCtorRep = etcr_float
|
|
; TypeCtorRep = etcr_char
|
|
; TypeCtorRep = etcr_string
|
|
; TypeCtorRep = etcr_void
|
|
; TypeCtorRep = etcr_stable_c_pointer
|
|
; TypeCtorRep = etcr_c_pointer
|
|
; TypeCtorRep = etcr_pred
|
|
; TypeCtorRep = etcr_func
|
|
; TypeCtorRep = etcr_ref
|
|
; TypeCtorRep = etcr_type_desc
|
|
; TypeCtorRep = etcr_pseudo_type_desc
|
|
; TypeCtorRep = etcr_type_ctor_desc
|
|
; TypeCtorRep = etcr_type_info
|
|
; TypeCtorRep = etcr_type_ctor_info
|
|
; TypeCtorRep = etcr_typeclass_info
|
|
; TypeCtorRep = etcr_base_typeclass_info
|
|
; TypeCtorRep = etcr_foreign
|
|
),
|
|
MaybeNumFunctors = no
|
|
;
|
|
( TypeCtorRep = etcr_hp
|
|
; TypeCtorRep = etcr_subgoal
|
|
; TypeCtorRep = etcr_ticket
|
|
),
|
|
unexpected($module, $pred, "type_ctor_rep not handled")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_functor(TypeDesc, FunctorNum, Name, Arity, ArgTypes) :-
|
|
get_functor_with_names(TypeDesc, FunctorNum, Name, Arity, ArgTypes, _).
|
|
|
|
get_functor_with_names(TypeDesc, FunctorNum, Name, Arity, ArgTypeDescs,
|
|
ArgNames) :-
|
|
TypeInfo = type_info_from_type_desc(TypeDesc),
|
|
MaybeResult = get_functor_with_names(TypeInfo, FunctorNum),
|
|
MaybeResult = yes({Name, Arity, ArgTypeInfos, ArgNames}),
|
|
ArgTypeDescs = type_descs_from_type_infos(ArgTypeInfos).
|
|
|
|
:- func get_functor_with_names(type_info, int) =
|
|
maybe({string, int, list(type_info), list(string)}).
|
|
|
|
get_functor_with_names(TypeInfo, NumFunctor) = Result :-
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
(
|
|
TypeCtorRep = etcr_du,
|
|
FunctorReps = TypeCtorInfo ^ type_ctor_functors,
|
|
( if
|
|
matching_du_functor_number(FunctorReps, NumFunctor, FunctorRep)
|
|
then
|
|
ArgInfos = FunctorRep ^ edu_arg_infos,
|
|
MapArgInfosToTypesNames =
|
|
( pred(ArgInfo::in, ArgTypeInfo::out, ArgName::out) is det :-
|
|
MaybePTI = ArgInfo ^ du_arg_type,
|
|
Info = yes({TypeInfo, no : pti_info(int)}),
|
|
ArgTypeInfo = concrete_type_info(Info, MaybePTI),
|
|
|
|
MaybeArgName = ArgInfo ^ du_arg_name,
|
|
(
|
|
MaybeArgName = yes(ArgName0),
|
|
ArgName = string.from_char_list(ArgName0)
|
|
;
|
|
MaybeArgName = no,
|
|
ArgName = ""
|
|
)
|
|
),
|
|
list.map2(MapArgInfosToTypesNames, ArgInfos, ArgTypes, ArgNames),
|
|
|
|
Name = string.from_char_list(FunctorRep ^ edu_name),
|
|
Arity = FunctorRep ^ edu_orig_arity,
|
|
Result = yes({Name, Arity, ArgTypes, ArgNames})
|
|
else
|
|
Result = no
|
|
)
|
|
;
|
|
TypeCtorRep = etcr_dummy,
|
|
Name = TypeCtorInfo ^ type_ctor_dummy_functor_name,
|
|
Arity = 0,
|
|
ArgTypes = [],
|
|
ArgNames = [],
|
|
Result = yes({Name, Arity, ArgTypes, ArgNames})
|
|
;
|
|
TypeCtorRep = etcr_tuple,
|
|
type_ctor_info_and_args(TypeInfo, _TypeCtorInfo, ArgTypes),
|
|
Name = "{}",
|
|
Arity = list.length(ArgTypes),
|
|
ArgNames = list.duplicate(Arity, ""),
|
|
Result = yes({Name, Arity, ArgTypes, ArgNames})
|
|
;
|
|
TypeCtorRep = etcr_list,
|
|
( if NumFunctor = 0 then
|
|
Name = "[]",
|
|
Arity = 0,
|
|
ArgTypes = [],
|
|
ArgNames = [],
|
|
Result = yes({Name, Arity, ArgTypes, ArgNames})
|
|
else if NumFunctor = 1 then
|
|
ArgTypeInfo = TypeInfo ^ type_info_index(1),
|
|
Name = "[|]",
|
|
Arity = 2,
|
|
ArgTypes = [ArgTypeInfo, TypeInfo],
|
|
ArgNames = ["", ""],
|
|
Result = yes({Name, Arity, ArgTypes, ArgNames})
|
|
else
|
|
Result = no
|
|
)
|
|
;
|
|
TypeCtorRep = etcr_eqv,
|
|
EqvTypeInfo = collapse_equivalences(TypeInfo),
|
|
Result = get_functor_with_names(EqvTypeInfo, NumFunctor)
|
|
;
|
|
( TypeCtorRep = etcr_array
|
|
; TypeCtorRep = etcr_int
|
|
; TypeCtorRep = etcr_float
|
|
; TypeCtorRep = etcr_char
|
|
; TypeCtorRep = etcr_string
|
|
; TypeCtorRep = etcr_void
|
|
; TypeCtorRep = etcr_stable_c_pointer
|
|
; TypeCtorRep = etcr_c_pointer
|
|
; TypeCtorRep = etcr_pred
|
|
; TypeCtorRep = etcr_func
|
|
; TypeCtorRep = etcr_ref
|
|
; TypeCtorRep = etcr_type_desc
|
|
; TypeCtorRep = etcr_pseudo_type_desc
|
|
; TypeCtorRep = etcr_type_ctor_desc
|
|
; TypeCtorRep = etcr_type_info
|
|
; TypeCtorRep = etcr_type_ctor_info
|
|
; TypeCtorRep = etcr_typeclass_info
|
|
; TypeCtorRep = etcr_base_typeclass_info
|
|
; TypeCtorRep = etcr_foreign
|
|
),
|
|
Result = no
|
|
;
|
|
( TypeCtorRep = etcr_hp
|
|
; TypeCtorRep = etcr_subgoal
|
|
; TypeCtorRep = etcr_ticket
|
|
),
|
|
unexpected($module, $pred, "type_ctor_rep not handled")
|
|
).
|
|
|
|
get_functor_ordinal(TypeDesc, FunctorNum, Ordinal) :-
|
|
TypeInfo = type_info_from_type_desc(TypeDesc),
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
(
|
|
TypeCtorRep = etcr_du,
|
|
FunctorReps = TypeCtorInfo ^ type_ctor_functors,
|
|
matching_du_functor_number(FunctorReps, FunctorNum, FunctorRep),
|
|
Ordinal = FunctorRep ^ edu_ordinal
|
|
;
|
|
TypeCtorRep = etcr_dummy,
|
|
FunctorNum = 0,
|
|
Ordinal = 0
|
|
;
|
|
TypeCtorRep = etcr_list,
|
|
(
|
|
Ordinal = 0,
|
|
FunctorNum = 0
|
|
;
|
|
Ordinal = 1,
|
|
FunctorNum = 1
|
|
)
|
|
;
|
|
TypeCtorRep = etcr_tuple,
|
|
FunctorNum = 0,
|
|
Ordinal = 0
|
|
).
|
|
|
|
get_functor_lex(TypeDesc, Ordinal, FunctorNum) :-
|
|
TypeInfo = type_info_from_type_desc(TypeDesc),
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
(
|
|
TypeCtorRep = etcr_du,
|
|
FunctorReps = TypeCtorInfo ^ type_ctor_functors,
|
|
matching_du_ordinal(FunctorReps, Ordinal, FunctorRep),
|
|
FunctorNum = FunctorRep ^ edu_lex
|
|
;
|
|
TypeCtorRep = etcr_dummy,
|
|
FunctorNum = 0,
|
|
Ordinal = 0
|
|
;
|
|
TypeCtorRep = etcr_list,
|
|
(
|
|
Ordinal = 0,
|
|
FunctorNum = 0
|
|
;
|
|
Ordinal = 1,
|
|
FunctorNum = 1
|
|
)
|
|
;
|
|
TypeCtorRep = etcr_tuple,
|
|
Ordinal = 0,
|
|
FunctorNum = 0
|
|
).
|
|
|
|
:- pred matching_du_ordinal(list(erlang_du_functor)::in,
|
|
functor_number_ordinal::in, erlang_du_functor::out) is semidet.
|
|
|
|
matching_du_ordinal(Fs, Ordinal, Functor) :-
|
|
list.index0(Fs, Ordinal, Functor),
|
|
% Sanity check.
|
|
( if Functor ^ edu_ordinal = Ordinal then
|
|
true
|
|
else
|
|
unexpected($module, $pred, "sanity check failed")
|
|
).
|
|
|
|
:- pred matching_du_functor_number(list(erlang_du_functor)::in,
|
|
functor_number_lex::in, erlang_du_functor::out) is semidet.
|
|
|
|
matching_du_functor_number([F | Fs], FunctorNum, Functor) :-
|
|
( if F ^ edu_lex = FunctorNum then
|
|
Functor = F
|
|
else
|
|
matching_du_functor_number(Fs, FunctorNum, Functor)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
construct(TypeDesc, Index, Args) = Term :-
|
|
TypeInfo = collapse_equivalences(unsafe_cast(TypeDesc)),
|
|
TypeCtorInfo = TypeInfo ^ type_ctor_info_evaled,
|
|
TypeCtorRep = TypeCtorInfo ^ type_ctor_rep,
|
|
|
|
(
|
|
TypeCtorRep = etcr_du,
|
|
Result = get_functor_with_names(TypeInfo, Index),
|
|
Result = yes({FunctorName, _FunctorArity, ArgTypes, _ArgNames}),
|
|
check_arg_types(Args, ArgTypes),
|
|
Term = construct_univ(TypeInfo, FunctorName, Args)
|
|
;
|
|
TypeCtorRep = etcr_dummy,
|
|
Index = 0,
|
|
Term = construct_univ(TypeInfo, "false", [])
|
|
;
|
|
TypeCtorRep = etcr_list,
|
|
( if Index = 1, Args = [Head, Tail] then
|
|
compare_type_infos((=),
|
|
univ_type_info(Head), TypeInfo ^ type_info_index(1)),
|
|
compare_type_infos((=), univ_type_info(Tail), TypeInfo),
|
|
Term = construct_list_cons_univ(TypeInfo, Head, Tail)
|
|
else
|
|
Index = 0,
|
|
Args = [],
|
|
Term = construct_empty_list_univ(TypeInfo)
|
|
)
|
|
;
|
|
TypeCtorRep = etcr_tuple,
|
|
Arity = TypeInfo ^ var_arity_type_info_arity,
|
|
check_tuple_arg_types(TypeInfo, 1 .. Arity, Args),
|
|
Term = construct_tuple_univ(TypeInfo, Args)
|
|
;
|
|
( TypeCtorRep = etcr_array
|
|
; TypeCtorRep = etcr_eqv
|
|
; TypeCtorRep = etcr_int
|
|
; TypeCtorRep = etcr_float
|
|
; TypeCtorRep = etcr_char
|
|
; TypeCtorRep = etcr_string
|
|
; TypeCtorRep = etcr_void
|
|
; TypeCtorRep = etcr_stable_c_pointer
|
|
; TypeCtorRep = etcr_c_pointer
|
|
; TypeCtorRep = etcr_pred
|
|
; TypeCtorRep = etcr_func
|
|
; TypeCtorRep = etcr_ref
|
|
; TypeCtorRep = etcr_type_desc
|
|
; TypeCtorRep = etcr_pseudo_type_desc
|
|
; TypeCtorRep = etcr_type_ctor_desc
|
|
; TypeCtorRep = etcr_type_info
|
|
; TypeCtorRep = etcr_type_ctor_info
|
|
; TypeCtorRep = etcr_typeclass_info
|
|
; TypeCtorRep = etcr_base_typeclass_info
|
|
; TypeCtorRep = etcr_foreign
|
|
; TypeCtorRep = etcr_hp
|
|
; TypeCtorRep = etcr_subgoal
|
|
; TypeCtorRep = etcr_ticket
|
|
),
|
|
unexpected($module, $pred,
|
|
"unable to construct something of type " ++ string(TypeCtorRep))
|
|
).
|
|
|
|
:- pred check_arg_types(list(univ)::in, list(type_info)::in) is semidet.
|
|
|
|
check_arg_types([], []).
|
|
check_arg_types([U | Us], [TI | TIs]) :-
|
|
compare_type_infos((=), univ_type_info(U), TI),
|
|
check_arg_types(Us, TIs).
|
|
|
|
:- pred check_tuple_arg_types(type_info::in,
|
|
list(int)::in, list(univ)::in) is semidet.
|
|
|
|
check_tuple_arg_types(_, [], []).
|
|
check_tuple_arg_types(TypeInfo, [I | Is], [U | Us]) :-
|
|
compare_type_infos((=),
|
|
TypeInfo ^ var_arity_type_info_index(I), univ_type_info(U)),
|
|
check_tuple_arg_types(TypeInfo, Is, Us).
|
|
|
|
:- func univ_type_info(univ) = type_info.
|
|
|
|
:- pragma foreign_proc(erlang,
|
|
univ_type_info(Univ::in) = (TypeInfo::out),
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
{univ_cons, TypeInfo, _} = Univ
|
|
").
|
|
|
|
univ_type_info(_) = _ :-
|
|
private_builtin.sorry("univ_type_info").
|
|
|
|
% Construct a du type and store it in a univ.
|
|
%
|
|
:- func construct_univ(type_info, string, list(univ)) = univ.
|
|
|
|
:- pragma foreign_proc(erlang,
|
|
construct_univ(TypeInfo::in, Functor::in, Args::in) = (Univ::out),
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
if
|
|
is_binary(Functor) ->
|
|
List = binary_to_list(Functor);
|
|
true ->
|
|
List = Functor
|
|
end,
|
|
Univ = {univ_cons, TypeInfo, list_to_tuple(
|
|
[list_to_atom(List) | lists:map(fun univ_to_value/1, Args)])}
|
|
").
|
|
|
|
construct_univ(_, _, _) = _ :-
|
|
private_builtin.sorry("construct_univ").
|
|
|
|
% Construct a tuple and store it in a univ.
|
|
%
|
|
:- func construct_tuple_univ(type_info, list(univ)) = univ.
|
|
|
|
:- pragma foreign_proc(erlang,
|
|
construct_tuple_univ(TypeInfo::in, Args::in) = (Univ::out),
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
Univ = {univ_cons, TypeInfo,
|
|
list_to_tuple(lists:map(fun univ_to_value/1, Args))}
|
|
").
|
|
|
|
construct_tuple_univ(_, _) = _ :-
|
|
private_builtin.sorry("construct_tuple_univ").
|
|
|
|
% Construct a empty list and store it in a univ.
|
|
%
|
|
:- func construct_empty_list_univ(type_info) = univ.
|
|
|
|
:- pragma foreign_proc(erlang,
|
|
construct_empty_list_univ(TypeInfo::in) = (Univ::out),
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
Univ = {univ_cons, TypeInfo, []}
|
|
").
|
|
|
|
construct_empty_list_univ(_) = _ :-
|
|
private_builtin.sorry("construct_empty_list_univ").
|
|
|
|
% Construct a cons cell and store it in a univ.
|
|
%
|
|
:- func construct_list_cons_univ(type_info, univ, univ) = univ.
|
|
|
|
:- pragma foreign_proc(erlang,
|
|
construct_list_cons_univ(TypeInfo::in, H::in, T::in) = (Univ::out),
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
Univ = {univ_cons, TypeInfo, [univ_to_value(H) | univ_to_value(T)]}
|
|
").
|
|
|
|
construct_list_cons_univ(_, _, _) = _ :-
|
|
private_builtin.sorry("construct_list_cons_univ").
|
|
|
|
:- pragma foreign_code(erlang, "
|
|
% Get the value out of the univ.
|
|
% Note we assume that we've checked that the value is consistent
|
|
% with another type_info elsewhere,
|
|
% for example in check_arg_types and check_tuple_arg_types.
|
|
%
|
|
univ_to_value(Univ) ->
|
|
{univ_cons, _UnivTypeInfo, Value} = Univ,
|
|
Value.
|
|
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
construct_tuple_2(Args, ArgTypes, Arity) = Tuple :-
|
|
TypeInfo = unsafe_cast(type_of(_ : {})),
|
|
Tuple = construct_tuple_3(TypeInfo, Arity, ArgTypes, Args).
|
|
|
|
:- func construct_tuple_3(type_info, int, list(type_desc), list(univ)) = univ.
|
|
|
|
:- pragma foreign_proc(erlang,
|
|
construct_tuple_3(TI::in, Arity::in, ArgTypes::in, Args::in) = (Term::out),
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
% Get the type_ctor_info from the empty tuple type_info
|
|
% and use that to create the correct var_arity type_info.
|
|
|
|
TCI = element(?ML_ti_type_ctor_info, TI),
|
|
TupleTypeInfo = list_to_tuple([TCI, Arity | ArgTypes]),
|
|
|
|
Tuple = list_to_tuple(lists:map(fun univ_to_value/1, Args)),
|
|
|
|
Term = {univ_cons, TupleTypeInfo, Tuple}
|
|
").
|
|
|
|
construct_tuple_3(_, _, _, _) = _ :-
|
|
private_builtin.sorry("construct_tuple_3").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pragma foreign_decl("Erlang", "
|
|
% These are macros for efficiency.
|
|
|
|
% Location of element in a type_info
|
|
-define(ML_ti_type_ctor_info, 1).
|
|
-define(ML_ti_var_arity, 2).
|
|
|
|
% Location of elements in a type_ctor_info
|
|
-define(ML_tci_arity, 1).
|
|
-define(ML_tci_version, 2).
|
|
-define(ML_tci_unify_pred, 3).
|
|
-define(ML_tci_compare_pred, 4).
|
|
-define(ML_tci_module_name, 5).
|
|
-define(ML_tci_type_name, 6).
|
|
-define(ML_tci_type_ctor_rep, 7).
|
|
-define(ML_tci_details, 8).
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func type_info(T::unused) = (type_info::out) is det.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_info(_T::unused) = (TypeInfo::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
TypeInfo = TypeInfo_for_T
|
|
").
|
|
|
|
type_info(_) = type_info :-
|
|
det_unimplemented("type_info").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func type_ctor_info_evaled(type_info) = type_ctor_info_evaled.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_info_evaled(TypeInfo::in) = (TypeCtorInfo::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
% io:format(""~nTypeInfo: ~p~n"", [TypeInfo]),
|
|
|
|
% If the type_info is for a type with arity 0,
|
|
% then the type_info is already the type_ctor info.
|
|
% We evaluate the thunk to get the actual type_ctor_info data.
|
|
|
|
if
|
|
is_function(TypeInfo, 0) ->
|
|
TypeCtorInfo = TypeInfo();
|
|
true ->
|
|
FirstElement = element(?ML_ti_type_ctor_info, TypeInfo),
|
|
if
|
|
is_integer(FirstElement) ->
|
|
TypeCtorInfo = TypeInfo;
|
|
true ->
|
|
TypeCtorInfo = FirstElement()
|
|
end
|
|
end,
|
|
% io:format(""TypeInfo: ~p~nTypeCtorInfo: ~p~n"", [TypeInfo, TypeCtorInfo]),
|
|
void
|
|
").
|
|
|
|
type_ctor_info_evaled(_) = type_ctor_info_evaled :-
|
|
det_unimplemented("type_ctor_info_evaled").
|
|
|
|
:- func var_arity_type_info_arity(type_info) = int.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
var_arity_type_info_arity(TypeInfo::in) = (Arity::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Arity = element(?ML_ti_var_arity, TypeInfo)
|
|
").
|
|
|
|
var_arity_type_info_arity(_) = 0 :-
|
|
det_unimplemented("var_arity_type_info_arity").
|
|
|
|
% TI ^ type_info_index(I)
|
|
%
|
|
% Returns the I'th type_info from the given standard type_info TI.
|
|
% NOTE Indexes start at one.
|
|
%
|
|
:- func type_info_index(int, type_info) = type_info.
|
|
|
|
type_info_index(I, TI) = TI ^ unsafe_type_info_index(I + 1).
|
|
|
|
% TI ^ var_arity_type_info_index(I)
|
|
%
|
|
% Returns the I'th type_info from the given variable arity type_info TI.
|
|
% NOTE Indexes start at one.
|
|
%
|
|
:- func var_arity_type_info_index(int, type_info) = type_info.
|
|
|
|
var_arity_type_info_index(I, TI) = TI ^ unsafe_type_info_index(I + 2).
|
|
|
|
% Use type_info_index or var_arity_type_info_index, never this predicate
|
|
% directly.
|
|
%
|
|
:- func unsafe_type_info_index(int, type_info) = type_info.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
unsafe_type_info_index(Index::in, TypeInfo::in) = (SubTypeInfo::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SubTypeInfo = element(Index, TypeInfo)
|
|
").
|
|
|
|
unsafe_type_info_index(_, _) = type_info :-
|
|
det_unimplemented("unsafe_type_info_index").
|
|
|
|
:- func get_fixed_arity_arg_type_infos(type_info) = list(type_info).
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
get_fixed_arity_arg_type_infos(TypeInfo::in) = (Args::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
if
|
|
is_tuple(TypeInfo) ->
|
|
[_TypeCtorInfo | Args] = tuple_to_list(TypeInfo);
|
|
is_function(TypeInfo, 0) ->
|
|
Args = [] % zero arity type_info
|
|
end
|
|
").
|
|
|
|
get_fixed_arity_arg_type_infos(_) = _ :-
|
|
private_builtin.sorry("get_fixed_arity_arg_type_infos").
|
|
|
|
:- func get_var_arity_arg_type_infos(type_info) = list(type_info).
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
get_var_arity_arg_type_infos(TypeInfo::in) = (Args::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Args = lists:nthtail(?ML_ti_var_arity, tuple_to_list(TypeInfo))
|
|
").
|
|
|
|
get_var_arity_arg_type_infos(_) = _ :-
|
|
private_builtin.sorry("get_var_arity_arg_type_infos").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func type_ctor_rep(type_ctor_info_evaled) = erlang_type_ctor_rep.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_rep(TypeCtorInfo::in) = (TypeCtorRep::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
% io:format(""type_ctor_rep(~p)~n"", [TypeCtorInfo]),
|
|
TypeCtorRep = element(?ML_tci_type_ctor_rep, TypeCtorInfo),
|
|
% io:format(""type_ctor_rep(~p) = ~p~n"", [TypeCtorInfo, TypeCtorRep]),
|
|
void
|
|
").
|
|
|
|
type_ctor_rep(_) = _ :-
|
|
% This version is only used for back-ends for which there is no
|
|
% matching foreign_proc version.
|
|
private_builtin.sorry("type_ctor_rep").
|
|
|
|
:- some [P] func type_ctor_unify_pred(type_ctor_info_evaled) = P.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_unify_pred(TypeCtorInfo::in) = (UnifyPred::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
% The TypeInfo is never used so this is safe.
|
|
TypeInfo_for_P = 0,
|
|
UnifyPred = element(?ML_tci_unify_pred, TypeCtorInfo)
|
|
").
|
|
|
|
type_ctor_unify_pred(_) = "dummy value" :-
|
|
det_unimplemented("type_ctor_unify_pred").
|
|
|
|
:- some [P] func type_ctor_compare_pred(type_ctor_info_evaled) = P.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_compare_pred(TypeCtorInfo::in) = (ComparePred::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
% The TypeInfo is never used so this is safe
|
|
TypeInfo_for_P = 0,
|
|
ComparePred = element(?ML_tci_compare_pred, TypeCtorInfo)
|
|
").
|
|
|
|
type_ctor_compare_pred(_) = "dummy value" :-
|
|
det_unimplemented("type_ctor_compare_pred").
|
|
|
|
:- func type_ctor_module_name(type_ctor_info_evaled) = string.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_module_name(TypeCtorInfo::in) = (ModuleName::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
ModuleName = list_to_binary(element(?ML_tci_module_name, TypeCtorInfo))
|
|
").
|
|
|
|
type_ctor_module_name(_) = "dummy value" :-
|
|
det_unimplemented("type_ctor_module_name").
|
|
|
|
:- func type_ctor_type_name(type_ctor_info_evaled) = string.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_type_name(TypeCtorInfo::in) = (TypeName::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
TypeName = list_to_binary(element(?ML_tci_type_name, TypeCtorInfo))
|
|
").
|
|
|
|
type_ctor_type_name(_) = "dummy value" :-
|
|
det_unimplemented("type_ctor_type_name").
|
|
|
|
:- func type_ctor_arity(type_ctor_info_evaled) = int.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_arity(TypeCtorInfo::in) = (Arity::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Arity = element(?ML_tci_arity, TypeCtorInfo)
|
|
").
|
|
|
|
type_ctor_arity(_) = 0 :-
|
|
det_unimplemented("type_ctor_arity").
|
|
|
|
:- func type_ctor_functors(type_ctor_info_evaled) = list(erlang_du_functor).
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_functors(TypeCtorInfo::in) = (Functors::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Functors = element(?ML_tci_details, TypeCtorInfo)
|
|
").
|
|
|
|
type_ctor_functors(_) = [] :-
|
|
det_unimplemented("type_ctor_functors").
|
|
|
|
:- func type_ctor_dummy_functor_name(type_ctor_info_evaled) = string.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_dummy_functor_name(TypeCtorInfo::in) = (Functor::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Functor = list_to_binary(element(?ML_tci_details, TypeCtorInfo))
|
|
").
|
|
|
|
type_ctor_dummy_functor_name(_) = "dummy value" :-
|
|
det_unimplemented("type_ctor_dummy_functor_name").
|
|
|
|
:- func type_ctor_eqv_type(type_ctor_info_evaled) = maybe_pseudo_type_info.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
type_ctor_eqv_type(TypeCtorInfo::in) = (EqvType::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
EqvType = element(?ML_tci_details, TypeCtorInfo)
|
|
").
|
|
|
|
type_ctor_eqv_type(_) = plain(type_info_thunk) :-
|
|
det_unimplemented("type_ctor_eqv_type").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Get a subterm term, given its type_info, the original term, its index
|
|
% and the start region size.
|
|
%
|
|
:- some [T] func get_subterm(type_info, U, int, int) = T.
|
|
|
|
get_subterm(_::in, _::in, _::in, _::in) = (42::out) :-
|
|
det_unimplemented("get_subterm").
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
get_subterm(TypeInfo::in, Term::in, Index::in, ExtraArgs::in) = (Arg::out),
|
|
[promise_pure],
|
|
"
|
|
% TypeInfo_for_U to avoid compiler warning
|
|
|
|
TypeInfo_for_T = TypeInfo,
|
|
case Term of
|
|
% If there are any extra arguments then we would not use the list
|
|
% syntax.
|
|
[A | _] when Index =:= 1 ->
|
|
Arg = A;
|
|
[_ | B] when Index =:= 2 ->
|
|
Arg = B;
|
|
|
|
_ when is_tuple(Term) ->
|
|
Arg = element(Index + ExtraArgs, Term)
|
|
end
|
|
").
|
|
|
|
:- func unsafe_cast(T) = U.
|
|
|
|
unsafe_cast(T) = U :-
|
|
private_builtin.unsafe_type_cast(T, U).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Implement generic calls -- we could use call/N but then we would
|
|
% have to create a real closure.
|
|
%
|
|
% We first give "unimplemented" definitions in Mercury, which will be
|
|
% used by default.
|
|
|
|
:- pred semidet_call_3(P::in, T::in, U::in) is semidet.
|
|
semidet_call_3(_::in, _::in, _::in) :-
|
|
semidet_unimplemented("semidet_call_3").
|
|
|
|
:- pred semidet_call_4(P::in, A::in, T::in, U::in) is semidet.
|
|
semidet_call_4(_::in, _::in, _::in, _::in) :-
|
|
semidet_unimplemented("semidet_call_4").
|
|
|
|
:- pred semidet_call_5(P::in, A::in, B::in, T::in, U::in) is semidet.
|
|
semidet_call_5(_::in, _::in, _::in, _::in, _::in) :-
|
|
semidet_unimplemented("semidet_call_5").
|
|
|
|
:- pred semidet_call_6(P::in, A::in, B::in, C::in, T::in, U::in) is semidet.
|
|
semidet_call_6(_::in, _::in, _::in, _::in, _::in, _::in) :-
|
|
semidet_unimplemented("semidet_call_6").
|
|
|
|
:- pred semidet_call_7(P::in, A::in, B::in, C::in, D::in, T::in, U::in)
|
|
is semidet.
|
|
semidet_call_7(_::in, _::in, _::in, _::in, _::in, _::in, _::in) :-
|
|
semidet_unimplemented("semidet_call_7").
|
|
|
|
:- pred semidet_call_8(P::in, A::in, B::in, C::in, D::in, E::in, T::in, U::in)
|
|
is semidet.
|
|
semidet_call_8(_::in, _::in, _::in, _::in, _::in, _::in, _::in, _::in) :-
|
|
semidet_unimplemented("semidet_call_8").
|
|
|
|
:- pred result_call_4(P::in, comparison_result::out,
|
|
T::in, U::in) is det.
|
|
result_call_4(_::in, (=)::out, _::in, _::in) :-
|
|
det_unimplemented("result_call_4").
|
|
|
|
:- pred result_call_5(P::in, comparison_result::out,
|
|
A::in, T::in, U::in) is det.
|
|
result_call_5(_::in, (=)::out, _::in, _::in, _::in) :-
|
|
det_unimplemented("comparison_result").
|
|
|
|
:- pred result_call_6(P::in, comparison_result::out,
|
|
A::in, B::in, T::in, U::in) is det.
|
|
result_call_6(_::in, (=)::out, _::in, _::in, _::in, _::in) :-
|
|
det_unimplemented("comparison_result").
|
|
|
|
:- pred result_call_7(P::in, comparison_result::out,
|
|
A::in, B::in, C::in, T::in, U::in) is det.
|
|
result_call_7(_::in, (=)::out, _::in, _::in, _::in, _::in, _::in) :-
|
|
det_unimplemented("comparison_result").
|
|
|
|
:- pred result_call_8(P::in, comparison_result::out,
|
|
A::in, B::in, C::in, D::in, T::in, U::in) is det.
|
|
result_call_8(_::in, (=)::out, _::in, _::in, _::in, _::in, _::in, _::in) :-
|
|
det_unimplemented("comparison_result").
|
|
|
|
:- pred result_call_9(P::in, comparison_result::out,
|
|
A::in, B::in, C::in, D::in, E::in, T::in, U::in) is det.
|
|
result_call_9(_::in, (=)::out, _::in, _::in, _::in, _::in, _::in,
|
|
_::in, _::in) :-
|
|
det_unimplemented("result_call_9").
|
|
|
|
:- pred semidet_unimplemented(string::in) is semidet.
|
|
|
|
semidet_unimplemented(S) :-
|
|
( semidet_succeed ->
|
|
unexpected($module, $pred, "unimplemented: " ++ S)
|
|
;
|
|
semidet_succeed
|
|
).
|
|
|
|
:- pred det_unimplemented(string::in) is det.
|
|
|
|
det_unimplemented(S) :-
|
|
( semidet_succeed ->
|
|
unexpected($module, $pred, "unimplemented: " ++ S)
|
|
;
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% We override the above definitions in the Erlang backend.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
semidet_call_3(Pred::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR = case Pred(X, Y) of {} -> true; fail -> false end
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
semidet_call_4(Pred::in, A::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR = case Pred(A, X, Y) of {} -> true; fail -> false end
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
semidet_call_5(Pred::in, A::in, B::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR = case Pred(A, B, X, Y) of {} -> true; fail -> false end
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
semidet_call_6(Pred::in, A::in, B::in, C::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR =
|
|
case Pred(A, B, C, X, Y) of
|
|
{} -> true;
|
|
fail -> false
|
|
end
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
semidet_call_7(Pred::in, A::in, B::in, C::in, D::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR =
|
|
case Pred(A, B, C, D, X, Y) of
|
|
{} -> true;
|
|
fail -> false
|
|
end
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
semidet_call_8(Pred::in, A::in, B::in, C::in, D::in, E::in,
|
|
X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
SUCCESS_INDICATOR =
|
|
case Pred(A, B, C, D, E, X, Y) of
|
|
{} -> true;
|
|
fail -> false
|
|
end
|
|
").
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
result_call_4(Pred::in, Res::out, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Res = Pred(X, Y)
|
|
").
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
result_call_5(Pred::in, Res::out, A::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Res = Pred(A, X, Y)
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
result_call_6(Pred::in, Res::out, A::in, B::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Res = Pred(A, B, X, Y)
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
result_call_7(Pred::in, Res::out, A::in, B::in, C::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Res = Pred(A, B, C, X, Y)
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
result_call_8(Pred::in, Res::out, A::in, B::in, C::in, D::in, X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Res = Pred(A, B, C, D, X, Y)
|
|
").
|
|
:- pragma foreign_proc("Erlang",
|
|
result_call_9(Pred::in, Res::out, A::in, B::in, C::in, D::in, E::in,
|
|
X::in, Y::in),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Res = Pred(A, B, C, D, E, X, Y)
|
|
").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred det_dynamic_cast(T::in, U::out) is det.
|
|
|
|
det_dynamic_cast(Term, Actual) :-
|
|
type_to_univ(Term, Univ),
|
|
det_univ_to_type(Univ, Actual).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% These types have to be kept in sync with the corresponding types in
|
|
% compiler/erlang_rtti.m
|
|
%
|
|
|
|
:- import_module maybe.
|
|
|
|
:- type erlang_atom.
|
|
:- pragma foreign_type("Erlang", erlang_atom, "").
|
|
:- type erlang_atom
|
|
---> erlang_atom.
|
|
|
|
:- type erlang_du_functor
|
|
---> erlang_du_functor(
|
|
edu_name :: list(char),
|
|
edu_orig_arity :: int,
|
|
edu_ordinal :: int,
|
|
edu_lex :: int,
|
|
edu_rep :: erlang_atom,
|
|
edu_arg_infos :: list(du_arg_info),
|
|
edu_exist_info :: maybe(exist_info)
|
|
).
|
|
|
|
:- type du_arg_info
|
|
---> du_arg_info(
|
|
du_arg_name :: maybe(list(char)),
|
|
du_arg_type :: maybe_pseudo_type_info,
|
|
du_arg_width :: arg_width
|
|
).
|
|
|
|
:- type exist_info
|
|
---> exist_info(
|
|
exist_num_plain_typeinfos :: int,
|
|
exist_num_typeinfos_in_tcis :: int,
|
|
exist_typeclass_constraints :: list(tc_constraint),
|
|
exist_typeinfo_locns :: list(exist_typeinfo_locn)
|
|
).
|
|
|
|
:- type tc_constraint
|
|
---> tc_constraint(
|
|
tcc_class_name :: tc_name,
|
|
tcc_types :: list(tc_type)
|
|
).
|
|
|
|
:- type exist_typeinfo_locn
|
|
---> plain_typeinfo(
|
|
int % The typeinfo is stored directly in the cell,
|
|
% at this offset.
|
|
)
|
|
; typeinfo_in_tci(
|
|
int, % The typeinfo is stored indirectly in the
|
|
% typeclass info stored at this offset in the cell.
|
|
|
|
int % To find the typeinfo inside the typeclass info
|
|
% structure, give this integer to the
|
|
% MR_typeclass_info_type_info macro.
|
|
).
|
|
|
|
:- type tc_name
|
|
---> tc_name(
|
|
tcn_module :: module_name,
|
|
tcn_name :: list(char),
|
|
tcn_arity :: int
|
|
).
|
|
|
|
:- type module_name == sym_name.
|
|
|
|
:- type sym_name
|
|
---> unqualified(list(char))
|
|
; qualified(sym_name, list(char)).
|
|
|
|
:- type tc_type == maybe_pseudo_type_info.
|
|
|
|
:- type maybe_pseudo_type_info
|
|
---> pseudo(pseudo_type_info_thunk)
|
|
; plain(type_info_thunk).
|
|
|
|
:- type arg_width
|
|
---> full_word
|
|
; double_word
|
|
; partial_word_first(int) % mask
|
|
; partial_word_shifted(int, int). % shift, mask
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type ti_info(T) == maybe({type_info, pti_info(T)}).
|
|
:- type pti_info(T) == maybe({erlang_du_functor, T}).
|
|
|
|
% Given a plain or pseudo type_info, return the concrete type_info
|
|
% which represents the type.
|
|
%
|
|
:- func concrete_type_info(ti_info(T), maybe_pseudo_type_info) = type_info.
|
|
|
|
concrete_type_info(Info, MaybePTI) = TypeInfo :-
|
|
(
|
|
MaybePTI = pseudo(PseudoThunk),
|
|
(
|
|
Info = yes({ParentTypeInfo, MaybeFunctorAndTerm}),
|
|
TypeInfo = eval_pseudo_type_info(
|
|
ParentTypeInfo, MaybeFunctorAndTerm, PseudoThunk)
|
|
;
|
|
Info = no,
|
|
unexpected($module, $pred, "missing parent type_info")
|
|
)
|
|
;
|
|
MaybePTI = plain(PlainThunk),
|
|
TypeInfo = eval_type_info_thunk(Info, PlainThunk)
|
|
).
|
|
|
|
:- func eval_pseudo_type_info(type_info,
|
|
pti_info(T), pseudo_type_info_thunk) = type_info.
|
|
|
|
eval_pseudo_type_info(ParentTypeInfo, MaybeFunctorAndTerm, Thunk) = TypeInfo :-
|
|
EvalResult = eval_pseudo_type_info_thunk(Thunk),
|
|
(
|
|
EvalResult = universal_type_info(N),
|
|
TypeInfo = ParentTypeInfo ^ type_info_index(N)
|
|
;
|
|
EvalResult = existential_type_info(N),
|
|
(
|
|
MaybeFunctorAndTerm = yes({Functor, Term}),
|
|
TypeInfo = exist_type_info(ParentTypeInfo, Functor, Term, N)
|
|
;
|
|
MaybeFunctorAndTerm = no,
|
|
% If we don't have the term available then leave the existential
|
|
% type variables in place, e.g. for get_functor_with_names.
|
|
TypeInfo = unsafe_cast(N)
|
|
)
|
|
;
|
|
EvalResult = pseudo_type_info(PseudoTypeInfo),
|
|
Info = yes({ParentTypeInfo, MaybeFunctorAndTerm}),
|
|
TypeInfo = eval_type_info(Info, unsafe_cast(PseudoTypeInfo))
|
|
).
|
|
|
|
:- func exist_type_info(type_info, erlang_du_functor, T, int) = type_info.
|
|
|
|
exist_type_info(TypeInfo, Functor, Term, N) = ArgTypeInfo :-
|
|
MaybeExist = Functor ^ edu_exist_info,
|
|
(
|
|
MaybeExist = yes(ExistInfo),
|
|
% The first existential type variable is numbered 512.
|
|
ExistLocn = list.det_index1(ExistInfo ^ exist_typeinfo_locns, N - 512),
|
|
(
|
|
ExistLocn = plain_typeinfo(X),
|
|
|
|
% Plain_typeinfo indexes start at 0, so we need to add two
|
|
% to get to the first index.
|
|
ArgTypeInfo = unsafe_cast(get_subterm(TypeInfo, Term, X, 2))
|
|
;
|
|
ExistLocn = typeinfo_in_tci(A, B),
|
|
|
|
% A starts at index 0 and measures from the start
|
|
% of the list of plain type_infos.
|
|
%
|
|
% B starts at index 1 and measures from the start
|
|
% of the type_class_info.
|
|
%
|
|
% Hence the addition of two extra arguments to find the
|
|
% type_class_info and then the addition of one extra
|
|
% arg to find the type_info in the type_class_info.
|
|
%
|
|
% Note it's safe to pass a bogus type_info to get_subterm
|
|
% because we never use the returned type_info.
|
|
|
|
Bogus = TypeInfo,
|
|
TypeClassInfo = get_subterm(Bogus, Term, A, 2),
|
|
ArgTypeInfo = unsafe_cast(get_subterm(Bogus, TypeClassInfo, B, 1))
|
|
)
|
|
;
|
|
MaybeExist = no,
|
|
unexpected($module, $pred, "no exist info")
|
|
).
|
|
|
|
:- func eval_type_info_thunk(ti_info(T), type_info_thunk) = type_info.
|
|
|
|
eval_type_info_thunk(I, Thunk) = TypeInfo :-
|
|
TI = eval_type_info_thunk_2(Thunk),
|
|
TypeInfo = eval_type_info(I, TI).
|
|
|
|
:- func eval_type_info(ti_info(T), type_info) = type_info.
|
|
|
|
eval_type_info(I, TI) = TypeInfo :-
|
|
TypeCtorInfo = TI ^ type_ctor_info_evaled,
|
|
( type_ctor_is_variable_arity(TypeCtorInfo) ->
|
|
Arity = TI ^ var_arity_type_info_arity,
|
|
ArgTypeInfos = list.map(var_arity_arg_type_info(I, TI), 1 .. Arity),
|
|
TypeInfo = create_var_arity_type_info(TypeCtorInfo, Arity,
|
|
ArgTypeInfos)
|
|
; TypeCtorInfo ^ type_ctor_arity = 0 ->
|
|
TypeInfo = TI
|
|
;
|
|
Arity = TypeCtorInfo ^ type_ctor_arity,
|
|
ArgTypeInfos = list.map(arg_type_info(I, TI), 1 .. Arity),
|
|
TypeInfo = create_type_info(TypeCtorInfo, ArgTypeInfos)
|
|
).
|
|
|
|
:- func var_arity_arg_type_info(ti_info(T), TypeInfo, int) = type_info.
|
|
|
|
var_arity_arg_type_info(Info, TypeInfo, Index) = ArgTypeInfo :-
|
|
MaybePTI = TypeInfo ^ var_arity_pseudo_type_info_index(Index),
|
|
ArgTypeInfo = concrete_type_info(Info, MaybePTI).
|
|
|
|
:- func arg_type_info(ti_info(T), TypeInfo, int) = type_info.
|
|
|
|
arg_type_info(Info, TypeInfo, Index) = ArgTypeInfo :-
|
|
MaybePTI = TypeInfo ^ pseudo_type_info_index(Index),
|
|
ArgTypeInfo = concrete_type_info(Info, MaybePTI).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func create_type_info(type_ctor_info_evaled, list(type_info)) = type_info.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
create_type_info(TypeCtorInfo::in, Args::in) = (TypeInfo::out),
|
|
[promise_pure, will_not_call_mercury, thread_safe],
|
|
"
|
|
% TypeCtorInfo was evaluated by eval_type_info, so we wrap it back up in a
|
|
% thunk. It may or may not be costly to do this, when we could have
|
|
% already used the one we extracted out of the type_info.
|
|
TypeCtorInfoFun = fun() -> TypeCtorInfo end,
|
|
TypeInfo =
|
|
case Args of
|
|
[] ->
|
|
TypeCtorInfoFun;
|
|
[_|_] ->
|
|
list_to_tuple([TypeCtorInfoFun | Args])
|
|
end
|
|
").
|
|
|
|
create_type_info(_, _) = type_info :-
|
|
det_unimplemented("create_type_info/2").
|
|
|
|
:- func create_var_arity_type_info(type_ctor_info_evaled,
|
|
int, list(type_info)) = type_info.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
create_var_arity_type_info(TypeCtorInfo::in, Arity::in, Args::in)
|
|
= (TypeInfo::out),
|
|
[promise_pure, will_not_call_mercury, thread_safe],
|
|
"
|
|
% TypeCtorInfo was evaluated by eval_type_info, so we wrap it back up in a
|
|
% thunk. It may or may not be costly to do this, when we could have
|
|
% already used the one we extracted out of the type_info.
|
|
TypeCtorInfoFun = fun() -> TypeCtorInfo end,
|
|
TypeInfo = list_to_tuple([TypeCtorInfoFun, Arity | Args])
|
|
").
|
|
|
|
create_var_arity_type_info(_, _, _) = type_info :-
|
|
det_unimplemented("create_var_arity_type_info/3").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% A pseudo_type_info can be represented in one of three ways.
|
|
% For a type with arity 0
|
|
% TypeCtorInfo
|
|
% a type with arity > 0
|
|
% { TypeCtorInfo, PseudoTypeInfo0, ..., PseudoTypeInfoN }
|
|
% a type with variable arity of size N
|
|
% { TypeCtorInfo, N, PseudoTypeInfo0, ..., PseudoTypeInfoN }
|
|
%
|
|
:- type pseudo_type_info.
|
|
:- pragma foreign_type("Erlang", pseudo_type_info, "").
|
|
:- type pseudo_type_info
|
|
---> pseudo_type_info.
|
|
|
|
% TI ^ pseudo_type_info_index(I)
|
|
%
|
|
% Returns the I'th maybe_pseudo_type_info from the given type_info
|
|
% or pseudo_type_info.
|
|
% NOTE Indexes start at one.
|
|
%
|
|
:- func pseudo_type_info_index(int, T) = maybe_pseudo_type_info.
|
|
|
|
pseudo_type_info_index(I, TI) = TI ^ unsafe_pseudo_type_info_index(I + 1).
|
|
|
|
% TI ^ var_arity_pseudo_type_info_index(I)
|
|
%
|
|
% NOTE Indexes start at one.
|
|
%
|
|
:- func var_arity_pseudo_type_info_index(int, T) = maybe_pseudo_type_info.
|
|
|
|
var_arity_pseudo_type_info_index(I, TI) =
|
|
TI ^ unsafe_pseudo_type_info_index(I + 2).
|
|
|
|
% Use pseudo_type_info_index or var_arity_pseudo_type_info_index, never
|
|
% this predicate directly.
|
|
%
|
|
:- func unsafe_pseudo_type_info_index(int, T) = maybe_pseudo_type_info.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
unsafe_pseudo_type_info_index(Index::in, TypeInfo::in) = (Maybe::out),
|
|
[will_not_call_mercury, promise_pure, thread_safe],
|
|
"
|
|
Maybe = element(Index, TypeInfo),
|
|
% io:format(""unsafe_pseudo_type_info_index(~p, ~p) = ~p~n"",
|
|
% [Index, TypeInfo, Maybe]),
|
|
void
|
|
").
|
|
|
|
unsafe_pseudo_type_info_index(_, _) = pseudo(pseudo_type_info_thunk) :-
|
|
det_unimplemented("unsafe_pseudo_type_info_index").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type pseudo_type_info_thunk.
|
|
:- pragma foreign_type("Erlang", pseudo_type_info_thunk, "").
|
|
:- type pseudo_type_info_thunk
|
|
---> pseudo_type_info_thunk.
|
|
|
|
:- type evaluated_pseudo_type_info_thunk
|
|
---> universal_type_info(int)
|
|
; existential_type_info(int)
|
|
; pseudo_type_info(pseudo_type_info).
|
|
|
|
:- func eval_pseudo_type_info_thunk(pseudo_type_info_thunk) =
|
|
evaluated_pseudo_type_info_thunk.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
eval_pseudo_type_info_thunk(Thunk::in) = (TypeInfo::out),
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
if
|
|
is_function(Thunk, 0) ->
|
|
MaybeTypeInfo = Thunk();
|
|
true ->
|
|
MaybeTypeInfo = Thunk
|
|
end,
|
|
TypeInfo =
|
|
if
|
|
is_integer(MaybeTypeInfo), MaybeTypeInfo < 512 ->
|
|
{ universal_type_info, MaybeTypeInfo };
|
|
is_integer(MaybeTypeInfo) ->
|
|
% We don't subtract 512 here so that the test output will be
|
|
% the same as for the C backends.
|
|
{ existential_type_info, MaybeTypeInfo };
|
|
true ->
|
|
{ pseudo_type_info, MaybeTypeInfo }
|
|
end,
|
|
% io:format(""eval_pseudo_type_info: ~p~n"", [TypeInfo]),
|
|
void
|
|
").
|
|
eval_pseudo_type_info_thunk(X) = erlang_rtti_implementation.unsafe_cast(X) :-
|
|
det_unimplemented("eval_pseudo_type_info/1").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type type_info_thunk.
|
|
:- pragma foreign_type("Erlang", type_info_thunk, "").
|
|
:- type type_info_thunk ---> type_info_thunk.
|
|
|
|
:- func eval_type_info_thunk_2(type_info_thunk) = type_info.
|
|
:- pragma foreign_proc("Erlang",
|
|
eval_type_info_thunk_2(Thunk::in) = (TypeInfo::out),
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
TypeInfo = Thunk(),
|
|
% io:format(""eval_type_info_thunk_2(~p) = ~p~n"", [Thunk, TypeInfo]),
|
|
void
|
|
").
|
|
eval_type_info_thunk_2(X) = erlang_rtti_implementation.unsafe_cast(X) :-
|
|
det_unimplemented("eval_type_info_thunk_2/1").
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- interface.
|
|
:- pred is_erlang_backend is semidet.
|
|
:- implementation.
|
|
|
|
:- pragma foreign_proc("Erlang",
|
|
is_erlang_backend,
|
|
[will_not_call_mercury, thread_safe, promise_pure],
|
|
"
|
|
SUCCESS_INDICATOR = true
|
|
").
|
|
|
|
is_erlang_backend :-
|
|
semidet_fail.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|