Files
mercury/compiler/typecheck_util.m
2025-10-23 17:12:22 +11:00

191 lines
7.4 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 1993-2012 The University of Melbourne.
% Copyright (C) 2014-2021, 2023-2025 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%---------------------------------------------------------------------------%
%
% File: typecheck_til.m.
%
% This file contains utility predicates used by the typechecker.
%
%---------------------------------------------------------------------------%
:- module check_hlds.typecheck_util.
:- interface.
:- import_module check_hlds.type_assign.
:- import_module hlds.
:- import_module hlds.hlds_class.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module list.
%---------------------------------------------------------------------------%
:- func empty_hlds_constraint_db = hlds_constraint_db.
%---------------------------------------------------------------------------%
:- pred type_assign_fresh_type_var(prog_var::in, mer_type::out,
type_assign::in, type_assign::out) is det.
%---------------------------------------------------------------------------%
% Unify (with occurs check) two types in a type assignment
% and update the type bindings.
%
:- pred type_assign_unify_type(mer_type::in, mer_type::in,
type_assign::in, type_assign::out) is semidet.
%---------------------------------------------------------------------------%
:- pred type_assign_rename_apart(type_assign::in, tvarset::in,
type_assign::out, tvar_renaming::out) is det.
%---------------------------------------------------------------------------%
:- pred keep_type_assigns_where_var_can_have_type(prog_var::in, mer_type::in,
type_assign_set::in, type_assign_set::out) is det.
:- pred acc_type_assign_if_var_can_have_type(type_assign::in,
prog_var::in, mer_type::in,
type_assign_set::in, type_assign_set::out) is det.
%---------------------------------------------------------------------------%
% higher_order_pred_type(Purity, N,
% TypeVarSet, PredType, ArgTypes):
%
% Given Purity and an arity N, return
% TypeVarSet = {T1, T2, ..., TN},
% PredType = `Purity pred(T1, T2, ..., TN)', and
% ArgTypes = [T1, T2, ..., TN].
%
:- pred general_higher_order_pred_type(purity::in, int::in,
tvarset::out, mer_type::out, list(mer_type)::out) is det.
% higher_order_func_type(Purity, N,
% TypeVarSet, FuncType, ArgTypes, RetType):
%
% Given Purity and an arity N, return
% TypeVarSet = {T0, T1, T2, ..., TN},
% FuncType = `Purity func(T1, T2, ..., TN) = T0',
% ArgTypes = [T1, T2, ..., TN], and
% RetType = T0.
%
:- pred general_higher_order_func_type(purity::in, int::in,
tvarset::out, mer_type::out, list(mer_type)::out, mer_type::out) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module mdbcomp.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.prog_type.
:- import_module parse_tree.prog_type_construct.
:- import_module parse_tree.prog_type_unify.
:- import_module parse_tree.vartypes.
:- import_module map.
:- import_module maybe.
:- import_module varset.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
empty_hlds_constraint_db =
hlds_constraint_db([], [], map.init, map.init).
%---------------------------------------------------------------------------%
type_assign_fresh_type_var(Var, Type, !TypeAssign) :-
type_assign_get_var_types(!.TypeAssign, VarTypes0),
type_assign_get_typevarset(!.TypeAssign, TypeVarSet0),
varset.new_var(TypeVar, TypeVarSet0, TypeVarSet),
type_assign_set_typevarset(TypeVarSet, !TypeAssign),
Type = type_variable(TypeVar, kind_star),
add_var_type(Var, Type, VarTypes0, VarTypes1),
type_assign_set_var_types(VarTypes1, !TypeAssign).
%---------------------------------------------------------------------------%
type_assign_unify_type(X, Y, TypeAssign0, TypeAssign) :-
type_assign_get_existq_tvars(TypeAssign0, ExistQTVars),
type_assign_get_type_bindings(TypeAssign0, TypeBindings0),
type_unify(X, Y, ExistQTVars, TypeBindings0, TypeBindings),
type_assign_set_type_bindings(TypeBindings, TypeAssign0, TypeAssign).
%---------------------------------------------------------------------------%
type_assign_rename_apart(TypeAssign0, PredTypeVarSet,
TypeAssign, Renaming) :-
type_assign_get_typevarset(TypeAssign0, TypeVarSet0),
tvarset_merge_renaming(TypeVarSet0, PredTypeVarSet, TypeVarSet, Renaming),
type_assign_set_typevarset(TypeVarSet, TypeAssign0, TypeAssign).
%---------------------------------------------------------------------------%
keep_type_assigns_where_var_can_have_type(Var, Type, !TypeAssignSet) :-
acc_type_assigns_where_var_can_have_type(!.TypeAssignSet, Var, Type,
[], !:TypeAssignSet).
:- pred acc_type_assigns_where_var_can_have_type(type_assign_set::in,
prog_var::in, mer_type::in,
type_assign_set::in, type_assign_set::out) is det.
acc_type_assigns_where_var_can_have_type([], _, _, !TypeAssignSet).
acc_type_assigns_where_var_can_have_type([TypeAssign0 | TypeAssigns0],
Var, Type, !TypeAssignSet) :-
acc_type_assign_if_var_can_have_type(TypeAssign0, Var, Type,
!TypeAssignSet),
acc_type_assigns_where_var_can_have_type(TypeAssigns0,
Var, Type, !TypeAssignSet).
acc_type_assign_if_var_can_have_type(TypeAssign0, Var, Type, !TypeAssignSet) :-
type_assign_get_var_types(TypeAssign0, VarTypes0),
search_insert_var_type(Var, Type, MaybeOldVarType, VarTypes0, VarTypes),
(
MaybeOldVarType = yes(OldVarType),
( if
type_assign_unify_type(OldVarType, Type, TypeAssign0, TypeAssign1)
then
!:TypeAssignSet = [TypeAssign1 | !.TypeAssignSet]
else
!:TypeAssignSet = !.TypeAssignSet
)
;
MaybeOldVarType = no,
type_assign_set_var_types(VarTypes, TypeAssign0, TypeAssign),
!:TypeAssignSet = [TypeAssign | !.TypeAssignSet]
).
%---------------------------------------------------------------------------%
general_higher_order_pred_type(Purity, Arity,
TypeVarSet, PredType, ArgTypes) :-
varset.init(TypeVarSet0),
varset.new_vars(Arity, ArgTypeVars, TypeVarSet0, TypeVarSet),
% Argument types always have kind `star'.
prog_type.var_list_to_type_list(map.init, ArgTypeVars, ArgTypes),
construct_higher_order_type(Purity, pf_predicate, ArgTypes, PredType).
general_higher_order_func_type(Purity, Arity,
TypeVarSet, FuncType, ArgTypes, RetType) :-
varset.init(TypeVarSet0),
varset.new_vars(Arity, ArgTypeVars, TypeVarSet0, TypeVarSet1),
varset.new_var(RetTypeVar, TypeVarSet1, TypeVarSet),
% Argument and return types always have kind `star'.
prog_type.var_list_to_type_list(map.init, ArgTypeVars, ArgTypes),
RetType = type_variable(RetTypeVar, kind_star),
construct_higher_order_func_type(Purity, ArgTypes, RetType, FuncType).
%---------------------------------------------------------------------------%
:- end_module check_hlds.typecheck_util.
%---------------------------------------------------------------------------%