Files
mercury/compiler/prog_type.m
Mark Brown cb2c3ec8bf Split typecheck.m into smaller modules.
Estimated hours taken: 3
Branches: main

Split typecheck.m into smaller modules.

compiler/typecheck.m:
	The main typechecking pass.

compiler/typecheck_errors.m:
	New module.  Error messages and debugging messages.

compiler/typecheck_info.m:
	New module.  The typecheck_info and type_assign data structures, plus
	some basic predicates.

compiler/typeclasses.m:
	New module.  The context reduction and improvement rules.

compiler/check_hlds.m:
	Register the new modules.

compiler/check_typeclass.m:
	Call typeclasses instead of typecheck to do context reduction.

compiler/prog_type.m:
	Move strip_builtin_qualifiers_from_type(_list) to here.

compiler/hlds_data.m:
	Define restrict_list_elements here instead of in typecheck.m and
	check_typeclass.m.
2005-04-23 06:29:48 +00:00

475 lines
15 KiB
Mathematica

%-----------------------------------------------------------------------------%
% Copyright (C) 2005 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
%
% Utility predicates dealing with types that do not require access to the
% HLDS. (The predicates that do are in type_util.m.)
%
%-----------------------------------------------------------------------------%
:- module parse_tree.prog_type.
:- interface.
:- import_module mdbcomp.prim_data.
:- import_module parse_tree.prog_data.
:- import_module list.
:- import_module map.
%-----------------------------------------------------------------------------%
% type_is_higher_order(Type, Purity, PredOrFunc, ArgTypes, EvalMeth):
% succeeds iff Type is a higher-order predicate or function type with
% the specified argument types (for functions, the return type is
% appended to the end of the argument types), purity, and
% evaluation method.
%
:- pred type_is_higher_order((type)::in, purity::out, pred_or_func::out,
lambda_eval_method::out, list(type)::out) is semidet.
% Succeed if the given type is a tuple type, returning
% the argument types.
%
:- pred type_is_tuple((type)::in, list(type)::out) is semidet.
% type_has_variable_arity_ctor(Type, TypeCtor, TypeArgs)
% Check if the principal type constructor of Type is of variable arity.
% If yes, return the type constructor as TypeCtor and its args as
% TypeArgs. If not, fail.
%
:- pred type_has_variable_arity_ctor((type)::in, type_ctor::out,
list(type)::out) is semidet.
% Given a non-variable type, return its type-id and argument types.
%
:- pred type_to_ctor_and_args((type)::in, type_ctor::out, list(type)::out)
is semidet.
% type_ctor_is_higher_order(TypeCtor, PredOrFunc) succeeds iff
% TypeCtor is a higher-order predicate or function type.
%
:- pred type_ctor_is_higher_order(type_ctor::in, purity::out, pred_or_func::out,
lambda_eval_method::out) is semidet.
% type_ctor_is_tuple(TypeCtor) succeeds iff TypeCtor is a tuple type.
%
:- pred type_ctor_is_tuple(type_ctor::in) is semidet.
% Given a variable type, return its type variable.
%
:- pred prog_type.var(type, tvar).
:- mode prog_type.var(in, out) is semidet.
:- mode prog_type.var(out, in) is det.
% Return a list of the type variables of a type.
%
:- pred prog_type.vars((type)::in, list(tvar)::out) is det.
% Given a type_ctor and a list of argument types,
% construct a type.
%
:- pred construct_type(type_ctor::in, list(type)::in, (type)::out) is det.
:- pred construct_higher_order_type(purity::in, pred_or_func::in,
lambda_eval_method::in, list(type)::in, (type)::out) is det.
:- pred construct_higher_order_pred_type(purity::in, lambda_eval_method::in,
list(type)::in, (type)::out) is det.
:- pred construct_higher_order_func_type(purity::in, lambda_eval_method::in,
list(type)::in, (type)::in, (type)::out) is det.
% Make error messages more readable by removing "builtin."
% qualifiers.
%
:- pred strip_builtin_qualifiers_from_type((type)::in, (type)::out) is det.
:- pred strip_builtin_qualifiers_from_type_list(list(type)::in,
list(type)::out) is det.
%-----------------------------------------------------------------------------%
%
% Utility predicates dealing with typeclass constraints.
%
:- pred apply_rec_subst_to_prog_constraints(tsubst::in, prog_constraints::in,
prog_constraints::out) is det.
:- pred apply_rec_subst_to_prog_constraint_list(tsubst::in,
list(prog_constraint)::in, list(prog_constraint)::out) is det.
:- pred apply_rec_subst_to_prog_constraint(tsubst::in, prog_constraint::in,
prog_constraint::out) is det.
:- pred apply_subst_to_prog_constraints(tsubst::in, prog_constraints::in,
prog_constraints::out) is det.
:- pred apply_subst_to_prog_constraint_list(tsubst::in,
list(prog_constraint)::in, list(prog_constraint)::out) is det.
:- pred apply_subst_to_prog_constraint(tsubst::in, prog_constraint::in,
prog_constraint::out) is det.
:- pred apply_variable_renaming_to_prog_constraints(map(tvar, tvar)::in,
prog_constraints::in, prog_constraints::out) is det.
:- pred apply_variable_renaming_to_prog_constraint_list(map(tvar, tvar)::in,
list(prog_constraint)::in, list(prog_constraint)::out) is det.
:- pred apply_variable_renaming_to_prog_constraint(map(tvar, tvar)::in,
prog_constraint::in, prog_constraint::out) is det.
% constraint_list_get_tvars(Constraints, TVars):
% return the list of type variables contained in a
% list of constraints
%
:- pred constraint_list_get_tvars(list(prog_constraint)::in, list(tvar)::out)
is det.
% constraint_get_tvars(Constraint, TVars):
% return the list of type variables contained in a constraint.
%
:- pred constraint_get_tvars(prog_constraint::in, list(tvar)::out) is det.
:- pred get_unconstrained_tvars(list(tvar)::in, list(prog_constraint)::in,
list(tvar)::out) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module parse_tree.prog_io.
:- import_module parse_tree.prog_out.
:- import_module parse_tree.prog_util.
:- import_module std_util.
:- import_module term.
%-----------------------------------------------------------------------------%
type_is_higher_order(Type, Purity, PredOrFunc, EvalMethod, PredArgTypes) :-
(
Type = term.functor(term.atom(PurityName), [BaseType], _),
purity_name(Purity0, PurityName),
type_is_higher_order_2(BaseType,
PredOrFunc0, EvalMethod0, PredArgTypes0)
->
Purity = Purity0,
PredOrFunc = PredOrFunc0,
EvalMethod = EvalMethod0,
PredArgTypes = PredArgTypes0
;
Purity = (pure),
type_is_higher_order_2(Type,
PredOrFunc, EvalMethod, PredArgTypes)
).
% This parses a higher-order type without any purity indicator.
:- pred type_is_higher_order_2((type)::in, pred_or_func::out,
lambda_eval_method::out, list(type)::out) is semidet.
type_is_higher_order_2(Type, PredOrFunc, EvalMethod, PredArgTypes) :-
(
Type = term.functor(term.atom("="),
[FuncEvalAndArgs, FuncRetType], _)
->
get_lambda_eval_method_and_args("func", FuncEvalAndArgs,
EvalMethod, FuncArgTypes),
list.append(FuncArgTypes, [FuncRetType], PredArgTypes),
PredOrFunc = function
;
get_lambda_eval_method_and_args("pred",
Type, EvalMethod, PredArgTypes),
PredOrFunc = predicate
).
% From the type of a lambda expression, work out how it should
% be evaluated and extract the argument types.
:- pred get_lambda_eval_method_and_args(string::in, (type)::in,
lambda_eval_method::out, list(type)::out) is semidet.
get_lambda_eval_method_and_args(PorFStr, Type0, EvalMethod, ArgTypes) :-
Type0 = term.functor(term.atom(Functor), Args, _),
( Functor = PorFStr ->
EvalMethod = normal,
ArgTypes = Args
;
Args = [Type1],
Type1 = term.functor(term.atom(PorFStr), ArgTypes, _),
Functor = "aditi_bottom_up",
EvalMethod = (aditi_bottom_up)
).
type_has_variable_arity_ctor(Type, TypeCtor, TypeArgs) :-
(
type_is_higher_order(Type, _Purity, PredOrFunc, _,
TypeArgs0)
->
TypeArgs = TypeArgs0,
PredOrFuncStr = prog_out.pred_or_func_to_str(PredOrFunc),
TypeCtor = unqualified(PredOrFuncStr) - 0
;
type_is_tuple(Type, TypeArgs1)
->
TypeArgs = TypeArgs1,
TypeCtor = unqualified("tuple") - 0
;
fail
).
type_to_ctor_and_args(Type, SymName - Arity, Args) :-
Type \= term.variable(_),
% higher order types may have representations where
% their arguments don't directly correspond to the
% arguments of the term.
(
type_is_higher_order(Type, Purity, PredOrFunc,
EvalMethod, PredArgTypes)
->
Args = PredArgTypes,
list.length(Args, Arity0),
adjust_func_arity(PredOrFunc, Arity, Arity0),
(
PredOrFunc = predicate,
PorFStr = "pred"
;
PredOrFunc = function,
PorFStr = "func"
),
SymName0 = unqualified(PorFStr),
(
EvalMethod = (aditi_bottom_up),
insert_module_qualifier("aditi_bottom_up", SymName0,
SymName1)
;
EvalMethod = normal,
SymName1 = SymName0
),
(
Purity = (pure),
SymName = SymName1
;
Purity = (semipure),
insert_module_qualifier("semipure", SymName1, SymName)
;
Purity = (impure),
insert_module_qualifier("impure", SymName1, SymName)
)
;
sym_name_and_args(Type, SymName, Args),
% `private_builtin:constraint' is introduced by polymorphism,
% and should only appear as the argument of a
% `typeclass:info/1' type.
% It behaves sort of like a type variable, so according to the
% specification of `type_to_ctor_and_args', it should
% cause failure. There isn't a definition in the type table.
\+ (
SymName = qualified(ModuleName, UnqualName),
UnqualName = "constraint",
mercury_private_builtin_module(PrivateBuiltin),
ModuleName = PrivateBuiltin
),
list.length(Args, Arity)
).
type_ctor_is_higher_order(SymName - _Arity, Purity, PredOrFunc, EvalMethod) :-
get_purity_and_eval_method(SymName, Purity, EvalMethod, PorFStr),
(
PorFStr = "pred",
PredOrFunc = predicate
;
PorFStr = "func",
PredOrFunc = function
).
:- pred get_purity_and_eval_method(sym_name::in, purity::out,
lambda_eval_method::out, string::out) is semidet.
get_purity_and_eval_method(SymName, Purity, EvalMethod, PorFStr) :-
(
SymName = qualified(unqualified(Qualifier), PorFStr),
(
Qualifier = "aditi_bottom_up",
EvalMethod = (aditi_bottom_up),
Purity = (pure)
;
Qualifier = "impure",
Purity = (impure),
EvalMethod = normal
;
Qualifier = "semipure",
Purity = (semipure),
EvalMethod = normal
)
;
SymName = unqualified(PorFStr),
EvalMethod = normal,
Purity = (pure)
).
type_is_tuple(Type, ArgTypes) :-
type_to_ctor_and_args(Type, TypeCtor, ArgTypes),
type_ctor_is_tuple(TypeCtor).
type_ctor_is_tuple(unqualified("{}") - _).
prog_type.var(term.variable(Var), Var).
prog_type.vars(Type, Tvars) :-
term.vars(Type, Tvars).
construct_type(TypeCtor, Args, Type) :-
(
type_ctor_is_higher_order(TypeCtor, Purity, PredOrFunc,
EvalMethod)
->
construct_higher_order_type(Purity, PredOrFunc, EvalMethod,
Args, Type)
;
TypeCtor = SymName - _,
construct_qualified_term(SymName, Args, Type)
).
construct_higher_order_type(Purity, PredOrFunc, EvalMethod, ArgTypes, Type) :-
(
PredOrFunc = predicate,
construct_higher_order_pred_type(Purity, EvalMethod, ArgTypes,
Type)
;
PredOrFunc = function,
pred_args_to_func_args(ArgTypes, FuncArgTypes, FuncRetType),
construct_higher_order_func_type(Purity, EvalMethod,
FuncArgTypes, FuncRetType, Type)
).
construct_higher_order_pred_type(Purity, EvalMethod, ArgTypes, Type) :-
construct_qualified_term(unqualified("pred"),
ArgTypes, Type0),
qualify_higher_order_type(EvalMethod, Type0, Type1),
Type = add_purity_annotation(Purity, Type1).
construct_higher_order_func_type(Purity, EvalMethod, ArgTypes, RetType, Type) :-
construct_qualified_term(unqualified("func"), ArgTypes, Type0),
qualify_higher_order_type(EvalMethod, Type0, Type1),
Type2 = term.functor(term.atom("="), [Type1, RetType],
term.context_init),
Type = add_purity_annotation(Purity, Type2).
:- func add_purity_annotation(purity, (type)) = (type).
add_purity_annotation(Purity, Type0) = Type :-
(
Purity = (pure),
Type = Type0
;
Purity = (semipure),
Type = term.functor(term.atom("semipure"), [Type0],
term.context_init)
;
Purity = (impure),
Type = term.functor(term.atom("impure"), [Type0],
term.context_init)
).
:- pred qualify_higher_order_type(lambda_eval_method::in, (type)::in,
(type)::out) is det.
qualify_higher_order_type(normal, Type, Type).
qualify_higher_order_type((aditi_bottom_up), Type0,
term.functor(term.atom("aditi_bottom_up"), [Type0], Context)) :-
term.context_init(Context).
strip_builtin_qualifiers_from_type(Type0, Type) :-
( type_to_ctor_and_args(Type0, TypeCtor0, Args0) ->
strip_builtin_qualifiers_from_type_list(Args0, Args),
TypeCtor0 = SymName0 - Arity,
(
SymName0 = qualified(Module, Name),
mercury_public_builtin_module(Module)
->
SymName = unqualified(Name)
;
SymName = SymName0
),
construct_type(SymName - Arity, Args, Type)
;
Type = Type0
).
strip_builtin_qualifiers_from_type_list(Types0, Types) :-
list__map(strip_builtin_qualifiers_from_type, Types0, Types).
%-----------------------------------------------------------------------------%
apply_rec_subst_to_prog_constraints(Subst, Constraints0, Constraints) :-
Constraints0 = constraints(UnivCs0, ExistCs0),
apply_rec_subst_to_prog_constraint_list(Subst, UnivCs0, UnivCs),
apply_rec_subst_to_prog_constraint_list(Subst, ExistCs0, ExistCs),
Constraints = constraints(UnivCs, ExistCs).
apply_rec_subst_to_prog_constraint_list(Subst, !Constraints) :-
list__map(apply_rec_subst_to_prog_constraint(Subst), !Constraints).
apply_rec_subst_to_prog_constraint(Subst, Constraint0, Constraint) :-
Constraint0 = constraint(ClassName, Types0),
term__apply_rec_substitution_to_list(Types0, Subst, Types),
Constraint = constraint(ClassName, Types).
apply_subst_to_prog_constraints(Subst,
constraints(UniversalCs0, ExistentialCs0),
constraints(UniversalCs, ExistentialCs)) :-
apply_subst_to_prog_constraint_list(Subst, UniversalCs0, UniversalCs),
apply_subst_to_prog_constraint_list(Subst, ExistentialCs0,
ExistentialCs).
apply_subst_to_prog_constraint_list(Subst, !Constraints) :-
list__map(apply_subst_to_prog_constraint(Subst), !Constraints).
apply_subst_to_prog_constraint(Subst, Constraint0, Constraint) :-
Constraint0 = constraint(ClassName, Types0),
term__apply_substitution_to_list(Types0, Subst, Types),
Constraint = constraint(ClassName, Types).
apply_variable_renaming_to_prog_constraints(Renaming, Constraints0,
Constraints) :-
Constraints0 = constraints(UnivConstraints0, ExistConstraints0),
apply_variable_renaming_to_prog_constraint_list(Renaming,
UnivConstraints0, UnivConstraints),
apply_variable_renaming_to_prog_constraint_list(Renaming,
ExistConstraints0, ExistConstraints),
Constraints = constraints(UnivConstraints, ExistConstraints).
apply_variable_renaming_to_prog_constraint_list(Renaming, !Constraints) :-
list.map(apply_variable_renaming_to_prog_constraint(Renaming),
!Constraints).
apply_variable_renaming_to_prog_constraint(Renaming, !Constraint) :-
!.Constraint = constraint(ClassName, ClassArgTypes0),
term.apply_variable_renaming_to_list(ClassArgTypes0, Renaming,
ClassArgTypes),
!:Constraint = constraint(ClassName, ClassArgTypes).
constraint_list_get_tvars(Constraints, TVars) :-
list.map(constraint_get_tvars, Constraints, TVarsList),
list.condense(TVarsList, TVars).
constraint_get_tvars(constraint(_Name, Args), TVars) :-
term.vars_list(Args, TVars).
get_unconstrained_tvars(Tvars, Constraints, Unconstrained) :-
constraint_list_get_tvars(Constraints, ConstrainedTvars),
list.delete_elems(Tvars, ConstrainedTvars, Unconstrained0),
list.remove_dups(Unconstrained0, Unconstrained).
%-----------------------------------------------------------------------------%
:- end_module prog_type.
%-----------------------------------------------------------------------------%