Files
mercury/compiler/var_table_hlds.m
Zoltan Somogyi d8a31e574e Move six utility modules from check_hlds to hlds.
compiler/inst_lookup.m:
compiler/inst_mode_type_prop.m:
compiler/inst_test.m:
compiler/inst_util.m:
compiler/mode_util.m:
compiler/type_util.m:
    Move these modules from the check_hlds package to the hlds package.
    The reason is that all the content of five of these modules, and
    most of the content of one module (inst_util.m) is not used
    exclusively during semantic checking passes. (A later diff
    should deal with the exception.) Some are used by the pass that
    builds the initial HLDS, and all are used by middle-end and backend
    passes. The move therefore reduces the number of inappropriate imports
    of the check_hlds package.

compiler/check_hlds.m:
compiler/hlds.m:
    Effect the transfer.

compiler/*.m:
    Conform to the changes above.
2025-10-08 23:07:13 +11:00

307 lines
12 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 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: var_table_hlds.m.
% Main author: zs.
%
% This module defines operations on var_tables that require access
% to the HLDS. (The var_table type itself, and most other operations on it,
% are defined in var_table.m, which is in the parse_tree package, which
% does not have access to the HLDS.)
%
%---------------------------------------------------------------------------%
:- module hlds.var_table_hlds.
:- interface.
:- import_module hlds.hlds_module.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.var_table.
:- import_module parse_tree.vartypes.
:- import_module assoc_list.
:- import_module list.
%---------------------------------------------------------------------------%
%
% These two predicates convert <varset, vartypes> pairs to var_tables,
% and vice versa. They are used by
%
% - ancient compiler passes (such as mode_constraints.) that could use
% var_tables but don't (because they were written way before var_tables),
% and
%
% - by code that constructs new clauses (such as unify/compare predicates
% and stubs) from HLDS code.
%
% The former will never be worth converting to use var_tables. The latter
% *could* be so converted, but it would require the code that now constructs
% clause_infos to construct HLDS predicates instead. This is definitely
% possible, since all the code that now constructs clause_infos should be
% able to figure out the exact types of all the variables in those clauses,
% but would require new code to explicitly materialize those types, instead of
% just leaving that job to the typechecker.
%
% Create a var_table from a varset/vartypes pair.
%
:- pred make_var_table(module_info::in, prog_varset::in, vartypes::in,
var_table::out) is det.
% Split up a var_table into a varset/vartypes pair.
%
:- pred split_var_table(var_table::in, prog_varset::out, vartypes::out) is det.
%---------------------------------------------------------------------------%
% Create a var_table from a varset and a list of variables
% with their types.
%
% The typechecking pass uses these predicates to record its results
% in pred_infos.
%
:- pred vars_types_to_var_table(module_info::in, prog_varset::in,
assoc_list(prog_var, mer_type)::in, var_table::out) is det.
:- pred corresponding_vars_types_to_var_table(module_info::in, prog_varset::in,
list(prog_var)::in, list(mer_type)::in, var_table::out) is det.
%---------------------------------------------------------------------------%
:- pred create_fresh_named_var(module_info::in, string::in, mer_type::in,
prog_var::out, var_table::in, var_table::out) is det.
:- pred create_fresh_var(module_info::in, mer_type::in,
prog_var::out, var_table::in, var_table::out) is det.
:- pred create_fresh_vars(module_info::in, list(mer_type)::in,
list(prog_var)::out, var_table::in, var_table::out) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.type_util.
:- import_module parse_tree.builtin_lib_types.
:- import_module parse_tree.prog_type.
:- import_module counter.
:- import_module int.
:- import_module map.
:- import_module pair.
:- import_module require.
:- import_module term.
:- import_module varset.
%---------------------------------------------------------------------------%
make_var_table(ModuleInfo, VarSet, VarTypes, VarTable) :-
vartypes_to_sorted_assoc_list(VarTypes, VarTypesAL),
make_var_table_loop(ModuleInfo, VarSet, 1, VarTypesAL,
[], RevVarTableAL0),
(
RevVarTableAL0 = [],
LastAllocVarNum0 = 0
;
RevVarTableAL0 = [Var - _ | _],
LastAllocVarNum0 = var_to_int(Var)
),
MaxVarInVarSet = varset.max_var(VarSet),
MaxVarNumInVarSet = var_to_int(MaxVarInVarSet),
( if MaxVarNumInVarSet > LastAllocVarNum0 then
LastAllocVarNum = MaxVarNumInVarSet,
extend_var_table_loop(VarSet, LastAllocVarNum0 + 1, LastAllocVarNum,
RevVarTableAL0, RevVarTableAL)
else
LastAllocVarNum = LastAllocVarNum0,
RevVarTableAL = RevVarTableAL0
),
counter.init(LastAllocVarNum + 1, Counter),
map.from_rev_sorted_assoc_list(RevVarTableAL, VarTableMap),
construct_var_table(Counter, VarTableMap, VarTable).
:- pred make_var_table_loop(module_info::in, prog_varset::in, int::in,
assoc_list(prog_var, mer_type)::in,
assoc_list(prog_var, var_table_entry)::in,
assoc_list(prog_var, var_table_entry)::out) is det.
make_var_table_loop(_, _, _, [], !RevVarTableAL).
make_var_table_loop(ModuleInfo, VarSet, CurVarNum, [Var - Type | VarsTypes0],
!RevVarTableAL) :-
VarNum = term.var_to_int(Var),
( if CurVarNum = VarNum then
( if varset.search_name(VarSet, Var, NamePrime) then
Name = NamePrime
else
Name = ""
),
IsDummy = is_type_a_dummy(ModuleInfo, Type),
Entry = vte(Name, Type, IsDummy),
!:RevVarTableAL = [Var - Entry | !.RevVarTableAL],
VarsTypes = VarsTypes0
else if CurVarNum < VarNum then
record_untyped_var(VarSet, CurVarNum, !RevVarTableAL),
% We did not Process Var in this iteration.
VarsTypes = [Var - Type | VarsTypes0]
else
unexpected($pred, "CurVarNum > VarNum")
),
make_var_table_loop(ModuleInfo, VarSet, CurVarNum + 1,
VarsTypes, !RevVarTableAL).
:- pred extend_var_table_loop(prog_varset::in, int::in, int::in,
assoc_list(prog_var, var_table_entry)::in,
assoc_list(prog_var, var_table_entry)::out) is det.
extend_var_table_loop(VarSet, CurVarNum, MaxVarNum, !RevVarTableAL) :-
( if CurVarNum =< MaxVarNum then
record_untyped_var(VarSet, CurVarNum, !RevVarTableAL),
extend_var_table_loop(VarSet, CurVarNum + 1, MaxVarNum, !RevVarTableAL)
else
true
).
% Record a variable number that was allocated in the varset,
% but whose type was not recorded.
%
% Before we started using var_tables, a lookup of such a variable
% would succeed in the varset but fail in the vartypes.
%
% The var_table we are constructing will have valid info for the name,
% but dummy info for the type.
%
:- pred record_untyped_var(prog_varset::in, int::in,
assoc_list(prog_var, var_table_entry)::in,
assoc_list(prog_var, var_table_entry)::out) is det.
record_untyped_var(VarSet, VarNum, !RevVarTableAL) :-
Var = force_construct_var(VarNum),
( if varset.search_name(VarSet, Var, NamePrime) then
Name = NamePrime
else
Name = ""
),
VarEntry = vte(Name, void_type, is_dummy_type),
!:RevVarTableAL = [Var - VarEntry | !.RevVarTableAL].
%---------------------------------------------------------------------------%
split_var_table(VarTable, VarSet, VarTypes) :-
deconstruct_var_table(VarTable, Counter, VarTableMap),
map.to_sorted_assoc_list(VarTableMap, VarsEntries),
split_var_table_loop(VarsEntries, [], RevVarTypes, [], RevVarNames),
vartypes_from_rev_sorted_assoc_list(RevVarTypes, VarTypes),
map.from_rev_sorted_assoc_list(RevVarNames, VarNameMap),
(
RevVarTypes = [],
LastVarNum = 0
;
RevVarTypes = [Var - _ | _],
LastVarNum = var_to_int(Var)
),
counter.allocate(NextVarNum, Counter, _),
expect(unify(LastVarNum + 1, NextVarNum), $pred,
"LastVarNum + 1 != NextVarNum"),
construct_varset(LastVarNum, VarNameMap, VarSet).
:- pred split_var_table_loop(assoc_list(prog_var, var_table_entry)::in,
assoc_list(prog_var, mer_type)::in, assoc_list(prog_var, mer_type)::out,
assoc_list(prog_var, string)::in, assoc_list(prog_var, string)::out)
is det.
split_var_table_loop([], !RevVarTypes, !RevVarNames).
split_var_table_loop([Var - Entry | VarsEntries],
!RevVarTypes, !RevVarNames) :-
Entry = vte(Name, Type, _IsDummy),
!:RevVarTypes = [Var - Type | !.RevVarTypes],
( if Name = "" then
true
else
!:RevVarNames = [Var - Name | !.RevVarNames]
),
split_var_table_loop(VarsEntries, !RevVarTypes, !RevVarNames).
%---------------------------------------------------------------------------%
vars_types_to_var_table(ModuleInfo, VarSet, VarsTypes, VarTable) :-
vars_types_to_vars_entries(ModuleInfo, VarSet, VarsTypes, [], VarsEntries),
list.sort(VarsEntries, SortedVarsEntries),
var_table_from_sorted_assoc_list(SortedVarsEntries, VarTable).
:- pred vars_types_to_vars_entries(module_info::in, prog_varset::in,
assoc_list(prog_var, mer_type)::in,
assoc_list(prog_var, var_table_entry)::in,
assoc_list(prog_var, var_table_entry)::out) is det.
vars_types_to_vars_entries(_, _, [], !VarsEntries).
vars_types_to_vars_entries(ModuleInfo, VarSet, [Var - Type | VarsTypes],
!VarsEntries) :-
( if varset.search_name(VarSet, Var, Name0) then
Name = Name0
else
Name = ""
),
IsDummy = is_type_a_dummy(ModuleInfo, Type),
Entry = vte(Name, Type, IsDummy),
!:VarsEntries = [Var - Entry | !.VarsEntries],
vars_types_to_vars_entries(ModuleInfo, VarSet, VarsTypes, !VarsEntries).
%---------------------------------------------------------------------------%
corresponding_vars_types_to_var_table(ModuleInfo, VarSet, Vars, Types,
VarTable) :-
corresponding_vars_types_to_vars_entries(ModuleInfo, VarSet, Vars, Types,
[], VarsEntries),
list.sort(VarsEntries, SortedVarsEntries),
var_table_from_sorted_assoc_list(SortedVarsEntries, VarTable).
:- pred corresponding_vars_types_to_vars_entries(module_info::in,
prog_varset::in, list(prog_var)::in, list(mer_type)::in,
assoc_list(prog_var, var_table_entry)::in,
assoc_list(prog_var, var_table_entry)::out) is det.
corresponding_vars_types_to_vars_entries(_, _, [], [], !VarsEntries).
corresponding_vars_types_to_vars_entries(_, _, [], [_ | _], !VarsEntries) :-
unexpected($pred, "length mismatch").
corresponding_vars_types_to_vars_entries(_, _, [_ | _], [], !VarsEntries) :-
unexpected($pred, "length mismatch").
corresponding_vars_types_to_vars_entries(ModuleInfo, VarSet,
[Var | Vars], [Type | Types], !VarsEntries) :-
( if varset.search_name(VarSet, Var, Name0) then
Name = Name0
else
Name = ""
),
IsDummy = is_type_a_dummy(ModuleInfo, Type),
Entry = vte(Name, Type, IsDummy),
!:VarsEntries = [Var - Entry | !.VarsEntries],
corresponding_vars_types_to_vars_entries(ModuleInfo, VarSet, Vars, Types,
!VarsEntries).
%---------------------------------------------------------------------------%
create_fresh_named_var(ModuleInfo, Name, Type, Var, !VarTable) :-
IsDummy = is_type_a_dummy(ModuleInfo, Type),
Entry = vte(Name, Type, IsDummy),
add_var_entry(Entry, Var, !VarTable).
create_fresh_var(ModuleInfo, Type, Var, !VarTable) :-
IsDummy = is_type_a_dummy(ModuleInfo, Type),
Entry = vte("", Type, IsDummy),
add_var_entry(Entry, Var, !VarTable).
create_fresh_vars(_, [], [], !VarTable).
create_fresh_vars(ModuleInfo, [Type | Types], [Var | Vars], !VarTable) :-
create_fresh_var(ModuleInfo, Type, Var, !VarTable),
create_fresh_vars(ModuleInfo, Types, Vars, !VarTable).
%---------------------------------------------------------------------------%
:- end_module hlds.var_table_hlds.
%---------------------------------------------------------------------------%