mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-18 10:53:40 +00:00
NEWS:
doc/reference_manual.texi:
Document the fact that the compiler now does such checks.
compiler/post_typecheck.m:
When propagating types into insts, ask inst_mode_type_prop.m to check
whether the types being propagated into user defined insts violate the
"for type_ctor" annotations on those insts.
Fix a bug in my earlier change. We want to propagate types into insts,
and check for applications of insts to values of inappropriate types
for lambda expressions. We used try to do it by traversing each procedure's
body goal, but this did nothing, because we copy goals to procedure bodies
in a pass that happens *after* the post-typecheck pass. During the
post-typecheck pass, these lambda expressions exist only in the predicate's
clauses, so that is where now we process them.
compiler/inst_mode_type_prop.m:
The code in this module is called not just from post_typecheck.m,
which needs this new check, but also from other modules, which do not.
To avoid excessive performance impact on the latter, make the
checking optional through a typeclass with two instances,
one of which prepares for and then does the checking, while the other
replaces all those operations with no-ops. Then use type_spec pragmas
to create two versions of all the predicates using this type class,
effectively creating two versions, one with the checks and the other
without the checks.
Change the name of all the exported predicates of this module
to specify whether they do these checks or not.
compiler/inst_lookup.m:
Conform to the changes above.
Note a possible performance problem.
compiler/add_special_pred.m:
compiler/inst_user.m:
Conform to the changes above.
tests/invalid/bad_type_for_inst.{m,err_exp}:
A test case for the error messages.
tests/invalid/Mmakefile:
Enable the new test case.
197 lines
7.5 KiB
Mathematica
197 lines
7.5 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-2012 The University of Melbourne.
|
|
% Copyright (C) 2015 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: inst_lookup.m.
|
|
% Author: fjh.
|
|
%
|
|
% This module looks up insts in the module_info, optionally expanding out
|
|
% references to user defined insts in the process.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module check_hlds.inst_lookup.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.prog_data.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Looking up named insts.
|
|
%
|
|
|
|
% Given a user-defined or compiler-defined inst name, look up the
|
|
% corresponding inst in the inst table.
|
|
%
|
|
:- pred inst_lookup(module_info::in, inst_name::in, mer_inst::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% inst_expand(ModuleInfo, Inst0, Inst) checks if the top-level part
|
|
% of the inst is a defined inst, and if so replaces it with the definition.
|
|
%
|
|
% This leaves insts with constrained_inst_vars at the top level unchanged.
|
|
%
|
|
:- pred inst_expand(module_info::in, mer_inst::in, mer_inst::out) is det.
|
|
|
|
% inst_expand_and_remove_constrained_inst_vars is the same as inst_expand
|
|
% except that it also removes constrained_inst_vars from the top level,
|
|
% replacing them with the constraining inst.
|
|
%
|
|
:- pred inst_expand_and_remove_constrained_inst_vars(module_info::in,
|
|
mer_inst::in, mer_inst::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds.inst_mode_type_prop.
|
|
:- import_module hlds.hlds_inst_mode.
|
|
:- import_module mdbcomp.
|
|
:- import_module parse_tree.prog_mode.
|
|
|
|
:- import_module list.
|
|
:- import_module map.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
inst_lookup(ModuleInfo, InstName, Inst) :-
|
|
(
|
|
InstName = unify_inst(Live, Real, InstA, InstB),
|
|
UnifyInstInfo = unify_inst_info(Live, Real, InstA, InstB),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_unify_insts(InstTable, UnifyInstTable),
|
|
lookup_unify_inst(UnifyInstTable, UnifyInstInfo, MaybeInstDet),
|
|
(
|
|
MaybeInstDet = inst_det_known(Inst, _)
|
|
;
|
|
MaybeInstDet = inst_det_unknown,
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = merge_inst(InstA, InstB),
|
|
MergeInstInfo = merge_inst_info(InstA, InstB),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_merge_insts(InstTable, MergeInstTable),
|
|
lookup_merge_inst(MergeInstTable, MergeInstInfo, MaybeInst),
|
|
(
|
|
MaybeInst = inst_known(Inst)
|
|
;
|
|
MaybeInst = inst_unknown,
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = ground_inst(SubInstName, Uniq, Live, Real),
|
|
GroundInstInfo = ground_inst_info(SubInstName, Uniq, Live, Real),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_ground_insts(InstTable, GroundInstTable),
|
|
lookup_ground_inst(GroundInstTable, GroundInstInfo, MaybeInstDet),
|
|
(
|
|
MaybeInstDet = inst_det_known(Inst, _)
|
|
;
|
|
MaybeInstDet = inst_det_unknown,
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = any_inst(SubInstName, Uniq, Live, Real),
|
|
AnyInstInfo = any_inst_info(SubInstName, Uniq, Live, Real),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_any_insts(InstTable, AnyInstTable),
|
|
lookup_any_inst(AnyInstTable, AnyInstInfo, MaybeInstDet),
|
|
(
|
|
MaybeInstDet = inst_det_known(Inst, _)
|
|
;
|
|
MaybeInstDet = inst_det_unknown,
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = shared_inst(SharedInstName),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_shared_insts(InstTable, SharedInstTable),
|
|
lookup_shared_inst(SharedInstTable, SharedInstName, MaybeInst),
|
|
(
|
|
MaybeInst = inst_known(Inst)
|
|
;
|
|
MaybeInst = inst_unknown,
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = mostly_uniq_inst(NondetLiveInstName),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_mostly_uniq_insts(InstTable, MostlyUniqInstTable),
|
|
lookup_mostly_uniq_inst(MostlyUniqInstTable, NondetLiveInstName,
|
|
MaybeInst),
|
|
(
|
|
MaybeInst = inst_known(Inst)
|
|
;
|
|
MaybeInst = inst_unknown,
|
|
Inst = defined_inst(InstName)
|
|
)
|
|
;
|
|
InstName = user_inst(Name, Args),
|
|
module_info_get_inst_table(ModuleInfo, InstTable),
|
|
inst_table_get_user_insts(InstTable, UserInstTable),
|
|
list.length(Args, Arity),
|
|
( if map.search(UserInstTable, inst_ctor(Name, Arity), InstDefn) then
|
|
InstDefn = hlds_inst_defn(_VarSet, Params, InstBody, _MMTC,
|
|
_Context, _Status),
|
|
InstBody = eqv_inst(Inst0),
|
|
inst_substitute_arg_list(Params, Args, Inst0, Inst)
|
|
else
|
|
Inst = abstract_inst(Name, Args)
|
|
)
|
|
;
|
|
InstName = typed_ground(Uniq, Type),
|
|
Inst0 = ground(Uniq, none_or_default_func),
|
|
propagate_unchecked_type_into_inst(ModuleInfo, Type, Inst0, Inst)
|
|
;
|
|
InstName = typed_inst(Type, TypedInstName),
|
|
inst_lookup(ModuleInfo, TypedInstName, Inst0),
|
|
% XXX Each invocation of inst_lookup expands out one inst_name.
|
|
% An inst_name of nonzeero arity will be applied to a list of insts,
|
|
% some of which may contain other inst_names, whose arguments
|
|
% may contain other inst_names, and so on.
|
|
%
|
|
% Such situations represent potential performance problems, because
|
|
% this call will propagate type information into *all* parts of Inst0,
|
|
% not just the top layer. This means that an inst inside argument
|
|
% lists of N nested inst_names will have type information propagated
|
|
% into it N times.
|
|
propagate_unchecked_type_into_inst(ModuleInfo, Type, Inst0, Inst)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
inst_expand(ModuleInfo, !Inst) :-
|
|
( if !.Inst = defined_inst(InstName) then
|
|
inst_lookup(ModuleInfo, InstName, !:Inst),
|
|
disable_warning [suspicious_recursion] (
|
|
inst_expand(ModuleInfo, !Inst)
|
|
)
|
|
else
|
|
true
|
|
).
|
|
|
|
inst_expand_and_remove_constrained_inst_vars(ModuleInfo, !Inst) :-
|
|
( if !.Inst = defined_inst(InstName) then
|
|
inst_lookup(ModuleInfo, InstName, !:Inst),
|
|
inst_expand(ModuleInfo, !Inst)
|
|
else if !.Inst = constrained_inst_vars(_, !:Inst) then
|
|
inst_expand(ModuleInfo, !Inst)
|
|
else
|
|
true
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module check_hlds.inst_lookup.
|
|
%---------------------------------------------------------------------------%
|