mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-18 15:26:31 +00:00
Estimated hours taken: 60 User-guided type specialization. compiler/prog_data.m: compiler/prog_io_pragma.m: compiler/modules.m: compiler/module_qual.m: compiler/mercury_to_mercury.m: Handle `:- pragma type_spec'. compiler/prog_io_pragma.m: Factor out some common code to parse predicate names with arguments. compiler/hlds_module.m: Added a field to the module_sub_info to hold information about user-requested type specializations, filled in by make_hlds.m and not used by anything after higher_order.m. compiler/make_hlds.m: For each `:- pragma type_spec' declaration, introduce a new predicate which just calls the predicate to be specialized with the specified argument types. This forces higher_order.m to produce the specialized versions. compiler/higher_order.m: Process the user-requested type specializations first to ensure that they get the correct names. Allow partial matches against user-specified versions, e.g. map__lookup(map(int, list(int)), int, list(int)) matches map__lookup(map(int, V), int, V). Perform specialization where a typeclass constraint matches a known instance, but the construction of the typeclass_info is done in the calling module. Give slightly more informative progress messages. compiler/dead_proc_elim.m: Remove specializations for dead procedures. compiler/prog_io_util.m: Change the definition of the `maybe1' and `maybe_functor' types to avoid the need for copying to convert between `maybe1' and `maybe1(generic)'. Changed the interface of `make_pred_name_with_context' to allow creation of predicate names for type specializations which describe the type substitution. compiler/make_hlds.m: compiler/prog_io_pragma.m: Make the specification of pragma declarations in error messages consistent. (There are probably some more to be fixed elsewhere for termination and tabling). compiler/intermod.m: Write type specialization pragmas for predicates declared in `.opt' files. compiler/mercury_to_mercury.m: Export `mercury_output_item' for use by intermod.m. compiler/options.m: Add an option `--user-guided-type-specialization' enabled with `-O2' or higher. compiler/handle_options.m: `--type-specialization' implies `--user-guided-type-specialization'. compiler/hlds_goal.m: Add predicates to construct constants. These are duplicated in several other places, I'll fix that as a separate change. compiler/type_util.m: Added functions `int_type/0', `string_type/0', `float_type/0' and `char_type/0' which return the builtin types. These are duplicated in several other places, I'll fix that as a separate change. library/private_builtin.m: Added `instance_constraint_from_typeclass_info/3' to extract the typeclass_infos for a constraint on an instance declaration. This is useful for specializing class method calls. Added `thread_safe' to various `:- pragma c_code's. Added `:- pragma inline' declarations for `builtin_compare_*', which are important for user-guided type specialization. (`builtin_unify_*' are simple enough to go in the `.opt' files automatically). compiler/polymorphism.m: `instance_constraint_from_typeclass_info/3' does not need type_infos. Add `instance_constraint_from_typeclass_info/3' to the list of `typeclass_info_manipulator's which higher_order.m can interpret. NEWS: doc/reference_manual.texi: doc/user_guide.texi Document the new pragma and option. tests/invalid/Mmakefile: tests/invalid/type_spec.m: tests/invalid/type_spec.err_exp: Test error reporting for invalid type specializations. tests/hard_coded/Mmakefile: tests/invalid/type_spec.m: tests/invalid/type_spec.exp: Test type specialization.
382 lines
14 KiB
Mathematica
382 lines
14 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-1999 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% main author: fjh
|
|
|
|
% various utility predicates acting on the parse tree data
|
|
% structure defined in prog_data.m.
|
|
|
|
:- module prog_util.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_pred, prog_data, term.
|
|
:- import_module std_util, list.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Returns the name of the module containing public builtins;
|
|
% originally this was "mercury_builtin", but it later became
|
|
% just "builtin", and it may eventually be renamed "std:builtin".
|
|
|
|
:- pred mercury_public_builtin_module(sym_name).
|
|
:- mode mercury_public_builtin_module(out) is det.
|
|
|
|
% Returns the name of the module containing private builtins;
|
|
% traditionally this was "mercury_builtin", but it later became
|
|
% "private_builtin", and it may eventually be renamed
|
|
% "std:private_builtin".
|
|
|
|
:- pred mercury_private_builtin_module(sym_name).
|
|
:- mode mercury_private_builtin_module(out) is det.
|
|
|
|
% Given a symbol name, return its unqualified name.
|
|
|
|
:- pred unqualify_name(sym_name, string).
|
|
:- mode unqualify_name(in, out) is det.
|
|
|
|
% sym_name_get_module_name(SymName, DefaultModName, ModName):
|
|
% Given a symbol name, return the module qualifier(s).
|
|
% If the symbol is unqualified, then return the specified default
|
|
% module name.
|
|
|
|
:- pred sym_name_get_module_name(sym_name, module_name, module_name).
|
|
:- mode sym_name_get_module_name(in, in, out) is det.
|
|
|
|
% string_to_sym_name(String, Separator, SymName):
|
|
% Convert a string, possibly prefixed with
|
|
% module qualifiers (separated by Separator),
|
|
% into a symbol name.
|
|
%
|
|
:- pred string_to_sym_name(string, string, sym_name).
|
|
:- mode string_to_sym_name(in, in, out) is det.
|
|
|
|
% match_sym_name(PartialSymName, CompleteSymName):
|
|
% succeeds iff there is some sequence of module qualifiers
|
|
% which when prefixed to PartialSymName gives CompleteSymName.
|
|
%
|
|
:- pred match_sym_name(sym_name, sym_name).
|
|
:- mode match_sym_name(in, in) is semidet.
|
|
|
|
% Given a possible module qualified sym_name and a list of
|
|
% argument types and a context, construct a term. This is
|
|
% used to construct types.
|
|
|
|
:- pred construct_qualified_term(sym_name, list(term(T)), term(T)).
|
|
:- mode construct_qualified_term(in, in, out) is det.
|
|
|
|
:- pred construct_qualified_term(sym_name, list(term(T)), prog_context, term(T)).
|
|
:- mode construct_qualified_term(in, in, in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% make_pred_name_with_context(ModuleName, Prefix, PredOrFunc, PredName,
|
|
% Line, Counter, SymName).
|
|
%
|
|
% Create a predicate name with context, e.g. for introduced
|
|
% lambda or deforestation predicates.
|
|
:- pred make_pred_name(module_name, string, maybe(pred_or_func),
|
|
string, new_pred_id, sym_name).
|
|
:- mode make_pred_name(in, in, in, in, in, out) is det.
|
|
|
|
% make_pred_name_with_context(ModuleName, Prefix, PredOrFunc, PredName,
|
|
% Line, Counter, SymName).
|
|
%
|
|
% Create a predicate name with context, e.g. for introduced
|
|
% lambda or deforestation predicates.
|
|
:- pred make_pred_name_with_context(module_name, string, pred_or_func,
|
|
string, int, int, sym_name).
|
|
:- mode make_pred_name_with_context(in, in, in, in, in, in, out) is det.
|
|
|
|
:- type new_pred_id
|
|
---> counter(int, int) % Line number, Counter
|
|
; type_subst(tvarset, type_subst)
|
|
.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% A pred declaration may contains just types, as in
|
|
% :- pred list__append(list(T), list(T), list(T)).
|
|
% or it may contain both types and modes, as in
|
|
% :- pred list__append(list(T)::in, list(T)::in,
|
|
% list(T)::output).
|
|
%
|
|
% This predicate takes the argument list of a pred declaration,
|
|
% splits it into two separate lists for the types and (if present)
|
|
% the modes.
|
|
|
|
:- type maybe_modes == maybe(list(mode)).
|
|
|
|
:- pred split_types_and_modes(list(type_and_mode), list(type), maybe_modes).
|
|
:- mode split_types_and_modes(in, out, out) is det.
|
|
|
|
:- pred split_type_and_mode(type_and_mode, type, maybe(mode)).
|
|
:- mode split_type_and_mode(in, out, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Perform a substitution on a goal.
|
|
|
|
:- pred prog_util__rename_in_goal(goal, prog_var, prog_var, goal).
|
|
:- mode prog_util__rename_in_goal(in, in, in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module mercury_to_mercury, (inst).
|
|
:- import_module bool, string, int, map, varset.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% We may eventually want to put the standard library into a package "std":
|
|
% mercury_public_builtin_module(M) :-
|
|
% M = qualified(unqualified("std"), "builtin"))).
|
|
% mercury_private_builtin_module(M) :-
|
|
% M = qualified(unqualified("std"), "private_builtin"))).
|
|
mercury_public_builtin_module(unqualified("builtin")).
|
|
mercury_private_builtin_module(unqualified("private_builtin")).
|
|
|
|
unqualify_name(unqualified(PredName), PredName).
|
|
unqualify_name(qualified(_ModuleName, PredName), PredName).
|
|
|
|
sym_name_get_module_name(unqualified(_), ModuleName, ModuleName).
|
|
sym_name_get_module_name(qualified(ModuleName, _PredName), _, ModuleName).
|
|
|
|
construct_qualified_term(qualified(Module, Name), Args, Context, Term) :-
|
|
construct_qualified_term(Module, [], Context, ModuleTerm),
|
|
UnqualifiedTerm = term__functor(term__atom(Name), Args, Context),
|
|
Term = term__functor(term__atom(":"),
|
|
[ModuleTerm, UnqualifiedTerm], Context).
|
|
construct_qualified_term(unqualified(Name), Args, Context, Term) :-
|
|
Term = term__functor(term__atom(Name), Args, Context).
|
|
|
|
|
|
construct_qualified_term(SymName, Args, Term) :-
|
|
term__context_init(Context),
|
|
construct_qualified_term(SymName, Args, Context, Term).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
split_types_and_modes(TypesAndModes, Types, MaybeModes) :-
|
|
split_types_and_modes_2(TypesAndModes, yes, Types, Modes, Result),
|
|
(
|
|
Result = yes
|
|
->
|
|
MaybeModes = yes(Modes)
|
|
;
|
|
MaybeModes = no
|
|
).
|
|
|
|
:- pred split_types_and_modes_2(list(type_and_mode), bool,
|
|
list(type), list(mode), bool).
|
|
:- mode split_types_and_modes_2(in, in, out, out, out) is det.
|
|
|
|
% T = type, M = mode, TM = combined type and mode
|
|
split_types_and_modes_2([], Result, [], [], Result).
|
|
split_types_and_modes_2([TM|TMs], Result0, [T|Ts], [M|Ms], Result) :-
|
|
split_type_and_mode(TM, Result0, T, M, Result1),
|
|
split_types_and_modes_2(TMs, Result1, Ts, Ms, Result).
|
|
|
|
% if a pred declaration specifies modes for some but
|
|
% not all of the arguments, then the modes are ignored
|
|
% - should this be an error instead?
|
|
|
|
:- pred split_type_and_mode(type_and_mode, bool, type, mode, bool).
|
|
:- mode split_type_and_mode(in, in, out, out, out) is det.
|
|
|
|
split_type_and_mode(type_only(T), _, T, (free -> free), no).
|
|
split_type_and_mode(type_and_mode(T,M), R, T, M, R).
|
|
|
|
split_type_and_mode(type_only(T), T, no).
|
|
split_type_and_mode(type_and_mode(T,M), T, yes(M)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
prog_util__rename_in_goal(Goal0 - Context, OldVar, NewVar, Goal - Context) :-
|
|
prog_util__rename_in_goal_expr(Goal0, OldVar, NewVar, Goal).
|
|
|
|
:- pred prog_util__rename_in_goal_expr(goal_expr, prog_var, prog_var,
|
|
goal_expr).
|
|
:- mode prog_util__rename_in_goal_expr(in, in, in, out) is det.
|
|
|
|
prog_util__rename_in_goal_expr((GoalA0, GoalB0), OldVar, NewVar,
|
|
(GoalA, GoalB)) :-
|
|
prog_util__rename_in_goal(GoalA0, OldVar, NewVar, GoalA),
|
|
prog_util__rename_in_goal(GoalB0, OldVar, NewVar, GoalB).
|
|
prog_util__rename_in_goal_expr((GoalA0 & GoalB0), OldVar, NewVar,
|
|
(GoalA & GoalB)) :-
|
|
prog_util__rename_in_goal(GoalA0, OldVar, NewVar, GoalA),
|
|
prog_util__rename_in_goal(GoalB0, OldVar, NewVar, GoalB).
|
|
prog_util__rename_in_goal_expr(true, _Var, _NewVar, true).
|
|
prog_util__rename_in_goal_expr((GoalA0; GoalB0), OldVar, NewVar,
|
|
(GoalA; GoalB)) :-
|
|
prog_util__rename_in_goal(GoalA0, OldVar, NewVar, GoalA),
|
|
prog_util__rename_in_goal(GoalB0, OldVar, NewVar, GoalB).
|
|
prog_util__rename_in_goal_expr(fail, _Var, _NewVar, fail).
|
|
prog_util__rename_in_goal_expr(not(Goal0), OldVar, NewVar, not(Goal)) :-
|
|
prog_util__rename_in_goal(Goal0, OldVar, NewVar, Goal).
|
|
prog_util__rename_in_goal_expr(some(Vars0, Goal0), OldVar, NewVar,
|
|
some(Vars, Goal)) :-
|
|
prog_util__rename_in_vars(Vars0, OldVar, NewVar, Vars),
|
|
prog_util__rename_in_goal(Goal0, OldVar, NewVar, Goal).
|
|
prog_util__rename_in_goal_expr(all(Vars0, Goal0), OldVar, NewVar,
|
|
all(Vars, Goal)) :-
|
|
prog_util__rename_in_vars(Vars0, OldVar, NewVar, Vars),
|
|
prog_util__rename_in_goal(Goal0, OldVar, NewVar, Goal).
|
|
prog_util__rename_in_goal_expr(implies(GoalA0, GoalB0), OldVar, NewVar,
|
|
implies(GoalA, GoalB)) :-
|
|
prog_util__rename_in_goal(GoalA0, OldVar, NewVar, GoalA),
|
|
prog_util__rename_in_goal(GoalB0, OldVar, NewVar, GoalB).
|
|
prog_util__rename_in_goal_expr(equivalent(GoalA0, GoalB0), OldVar, NewVar,
|
|
equivalent(GoalA, GoalB)) :-
|
|
prog_util__rename_in_goal(GoalA0, OldVar, NewVar, GoalA),
|
|
prog_util__rename_in_goal(GoalB0, OldVar, NewVar, GoalB).
|
|
prog_util__rename_in_goal_expr(if_then(Vars0, Cond0, Then0), OldVar, NewVar,
|
|
if_then(Vars, Cond, Then)) :-
|
|
prog_util__rename_in_vars(Vars0, OldVar, NewVar, Vars),
|
|
prog_util__rename_in_goal(Cond0, OldVar, NewVar, Cond),
|
|
prog_util__rename_in_goal(Then0, OldVar, NewVar, Then).
|
|
prog_util__rename_in_goal_expr(if_then_else(Vars0, Cond0, Then0, Else0),
|
|
OldVar, NewVar, if_then_else(Vars, Cond, Then, Else)) :-
|
|
prog_util__rename_in_vars(Vars0, OldVar, NewVar, Vars),
|
|
prog_util__rename_in_goal(Cond0, OldVar, NewVar, Cond),
|
|
prog_util__rename_in_goal(Then0, OldVar, NewVar, Then),
|
|
prog_util__rename_in_goal(Else0, OldVar, NewVar, Else).
|
|
prog_util__rename_in_goal_expr(call(SymName, Terms0, Purity), OldVar, NewVar,
|
|
call(SymName, Terms, Purity)) :-
|
|
term__substitute_list(Terms0, OldVar, term__variable(NewVar),
|
|
Terms).
|
|
prog_util__rename_in_goal_expr(unify(TermA0, TermB0), OldVar, NewVar,
|
|
unify(TermA, TermB)) :-
|
|
term__substitute(TermA0, OldVar, term__variable(NewVar),
|
|
TermA),
|
|
term__substitute(TermB0, OldVar, term__variable(NewVar),
|
|
TermB).
|
|
|
|
:- pred prog_util__rename_in_vars(list(prog_var), prog_var, prog_var,
|
|
list(prog_var)).
|
|
:- mode prog_util__rename_in_vars(in, in, in, out) is det.
|
|
|
|
prog_util__rename_in_vars([], _, _, []).
|
|
prog_util__rename_in_vars([Var0 | Vars0], OldVar, NewVar, [Var | Vars]) :-
|
|
( Var0 = OldVar ->
|
|
Var = NewVar
|
|
;
|
|
Var = Var0
|
|
),
|
|
prog_util__rename_in_vars(Vars0, OldVar, NewVar, Vars).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% This would be simpler if we had a string__rev_sub_string_search/3 pred.
|
|
% With that, we could search for underscores right-to-left,
|
|
% and construct the resulting symbol directly.
|
|
% Instead, we search for them left-to-right, and then call
|
|
% insert_module_qualifier to fix things up.
|
|
|
|
string_to_sym_name(String, ModuleSeparator, Result) :-
|
|
(
|
|
string__sub_string_search(String, ModuleSeparator, LeftLength),
|
|
LeftLength > 0
|
|
->
|
|
string__left(String, LeftLength, ModuleName),
|
|
string__length(String, StringLength),
|
|
string__length(ModuleSeparator, SeparatorLength),
|
|
RightLength is StringLength - LeftLength - SeparatorLength,
|
|
string__right(String, RightLength, Name),
|
|
string_to_sym_name(Name, ModuleSeparator, NameSym),
|
|
insert_module_qualifier(ModuleName, NameSym, Result)
|
|
;
|
|
Result = unqualified(String)
|
|
).
|
|
|
|
:- pred insert_module_qualifier(string, sym_name, sym_name).
|
|
:- mode insert_module_qualifier(in, in, out) is det.
|
|
|
|
insert_module_qualifier(ModuleName, unqualified(PlainName),
|
|
qualified(unqualified(ModuleName), PlainName)).
|
|
insert_module_qualifier(ModuleName, qualified(ModuleQual0, PlainName),
|
|
qualified(ModuleQual, PlainName)) :-
|
|
insert_module_qualifier(ModuleName, ModuleQual0, ModuleQual).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% match_sym_name(PartialSymName, CompleteSymName):
|
|
% succeeds iff there is some sequence of module qualifiers
|
|
% which when prefixed to PartialSymName gives CompleteSymName.
|
|
|
|
match_sym_name(qualified(Module1, Name), qualified(Module2, Name)) :-
|
|
match_sym_name(Module1, Module2).
|
|
match_sym_name(unqualified(Name), unqualified(Name)).
|
|
match_sym_name(unqualified(Name), qualified(_, Name)).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
make_pred_name_with_context(ModuleName, Prefix,
|
|
PredOrFunc, PredName, Line, Counter, SymName) :-
|
|
make_pred_name(ModuleName, Prefix, yes(PredOrFunc), PredName,
|
|
counter(Line, Counter), SymName).
|
|
|
|
make_pred_name(ModuleName, Prefix, MaybePredOrFunc, PredName,
|
|
NewPredId, SymName) :-
|
|
(
|
|
MaybePredOrFunc = yes(PredOrFunc),
|
|
(
|
|
PredOrFunc = predicate,
|
|
PFS = "pred"
|
|
;
|
|
PredOrFunc = function,
|
|
PFS = "func"
|
|
)
|
|
;
|
|
MaybePredOrFunc = no,
|
|
PFS = "pred_or_func"
|
|
),
|
|
(
|
|
NewPredId = counter(Line, Counter),
|
|
string__format("%d__%d", [i(Line), i(Counter)], PredIdStr)
|
|
;
|
|
NewPredId = type_subst(VarSet, TypeSubst),
|
|
SubstToString = lambda([SubstElem::in, SubstStr::out] is det, (
|
|
SubstElem = Var - Type,
|
|
varset__lookup_name(VarSet, Var, VarName),
|
|
mercury_type_to_string(VarSet, Type, TypeString),
|
|
string__append_list([VarName, " = ", TypeString],
|
|
SubstStr)
|
|
)),
|
|
list_to_string(SubstToString, TypeSubst, PredIdStr)
|
|
),
|
|
|
|
string__format("%s__%s__%s__%s",
|
|
[s(Prefix), s(PredIdStr), s(PFS), s(PredName)], Name),
|
|
SymName = qualified(ModuleName, Name).
|
|
|
|
:- pred list_to_string(pred(T, string), list(T), string).
|
|
:- mode list_to_string(pred(in, out) is det, in, out) is det.
|
|
|
|
list_to_string(Pred, List, String) :-
|
|
list_to_string_2(Pred, List, Strings, ["]"]),
|
|
string__append_list(["[" | Strings], String).
|
|
|
|
:- pred list_to_string_2(pred(T, string), list(T), list(string), list(string)).
|
|
:- mode list_to_string_2(pred(in, out) is det, in, out, in) is det.
|
|
|
|
list_to_string_2(_, []) --> [].
|
|
list_to_string_2(Pred, [T | Ts]) -->
|
|
{ call(Pred, T, String) },
|
|
[String],
|
|
( { Ts = [] } ->
|
|
[]
|
|
;
|
|
[", "],
|
|
list_to_string_2(Pred, Ts)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|