diff --git a/compiler/accumulator.m b/compiler/accumulator.m index d9953671f..2004fbd5f 100644 --- a/compiler/accumulator.m +++ b/compiler/accumulator.m @@ -1434,7 +1434,7 @@ accumulator__check_assoc_unify(assign(L, _R)) --> assoc_info_set_dynamic_set(DynamicSet). accumulator__check_assoc_unify(simple_test(_L, _R)) --> { fail }. -accumulator__check_assoc_unify(complicated_unify(_Modes, _Cat)) --> +accumulator__check_assoc_unify(complicated_unify(_Modes, _Cat, _)) --> { fail }. % XXX not sure what this should be. %-----------------------------------------------------------------------------% diff --git a/compiler/bytecode_gen.m b/compiler/bytecode_gen.m index 9f255a719..3f3aa1673 100644 --- a/compiler/bytecode_gen.m +++ b/compiler/bytecode_gen.m @@ -465,7 +465,7 @@ bytecode_gen__unify(simple_test(Var1, Var2), _, _, ByteInfo, Code) :- bytecode_gen__map_var(ByteInfo, Var1, ByteVar1), bytecode_gen__map_var(ByteInfo, Var2, ByteVar2), Code = node([test(ByteVar1, ByteVar2)]). -bytecode_gen__unify(complicated_unify(_, _), _Var, _RHS, _ByteInfo, _Code) :- +bytecode_gen__unify(complicated_unify(_,_,_), _Var, _RHS, _ByteInfo, _Code) :- error("complicated unifications should have been handled by polymorphism.m"). :- pred bytecode_gen__map_uni_modes(list(uni_mode)::in, list(prog_var)::in, diff --git a/compiler/check_typeclass.m b/compiler/check_typeclass.m index 05c1dc5ee..029a32aae 100644 --- a/compiler/check_typeclass.m +++ b/compiler/check_typeclass.m @@ -524,11 +524,13 @@ produce_auxiliary_procs(ClassVars, varset__init(VarSet0), make_n_fresh_vars("HeadVar__", PredArity, VarSet0, HeadVars, VarSet), map__from_corresponding_lists(HeadVars, ArgTypes, VarTypes), - DummyClausesInfo = clauses_info(VarSet, VarTypes, VarTypes, HeadVars, - DummyClause), + map__init(TI_VarMap), + map__init(TCI_VarMap), + ClausesInfo0 = clauses_info(VarSet, VarTypes, VarTypes, HeadVars, + DummyClause, TI_VarMap, TCI_VarMap), pred_info_init(ModuleName, PredName, PredArity, ArgTypeVars, - ExistQVars, ArgTypes, Cond, Context, DummyClausesInfo, Status, + ExistQVars, ArgTypes, Cond, Context, ClausesInfo0, Status, Markers, none, PredOrFunc, ClassContext, Proofs, User, PredInfo0), @@ -572,8 +574,7 @@ produce_auxiliary_procs(ClassVars, IntroducedGoal = IntroducedGoalExpr - GoalInfo ), IntroducedClause = clause(InstanceProcIds, IntroducedGoal, Context), - ClausesInfo = clauses_info(VarSet, VarTypes, VarTypes, HeadVars, - [IntroducedClause]), + clauses_info_set_clauses(ClausesInfo0, [IntroducedClause], ClausesInfo), pred_info_set_clauses_info(PredInfo1, ClausesInfo, PredInfo), module_info_get_predicate_table(ModuleInfo0, PredicateTable0), diff --git a/compiler/clause_to_proc.m b/compiler/clause_to_proc.m index 01e39af24..0bd885ffa 100644 --- a/compiler/clause_to_proc.m +++ b/compiler/clause_to_proc.m @@ -107,8 +107,17 @@ copy_module_clauses_to_procs(PredIds, ModuleInfo0, ModuleInfo) :- copy_module_clauses_to_procs_2([], Preds, Preds). copy_module_clauses_to_procs_2([PredId | PredIds], Preds0, Preds) :- map__lookup(Preds0, PredId, PredInfo0), - copy_clauses_to_procs(PredInfo0, PredInfo), - map__det_update(Preds0, PredId, PredInfo, Preds1), + ( + % don't process typeclass methods, because their proc_infos + % are generated already mode-correct + pred_info_get_markers(PredInfo0, PredMarkers), + check_marker(PredMarkers, class_method) + -> + Preds1 = Preds0 + ; + copy_clauses_to_procs(PredInfo0, PredInfo), + map__det_update(Preds0, PredId, PredInfo, Preds1) + ), copy_module_clauses_to_procs_2(PredIds, Preds1, Preds). @@ -131,7 +140,8 @@ copy_clauses_to_procs_2([ProcId | ProcIds], ClausesInfo, Procs0, Procs) :- copy_clauses_to_procs_2(ProcIds, ClausesInfo, Procs1, Procs). copy_clauses_to_proc(ProcId, ClausesInfo, Proc0, Proc) :- - ClausesInfo = clauses_info(VarSet, _, VarTypes, HeadVars, Clauses), + ClausesInfo = clauses_info(VarSet, _, VarTypes, HeadVars, Clauses, + TI_VarMap, TCI_VarMap), select_matching_clauses(Clauses, ProcId, MatchingClauses), get_clause_goals(MatchingClauses, GoalList), ( GoalList = [SingleGoal] -> @@ -181,7 +191,8 @@ copy_clauses_to_proc(ProcId, ClausesInfo, Proc0, Proc) :- map__init(Empty), Goal = disj(GoalList, Empty) - GoalInfo ), - proc_info_set_body(Proc0, VarSet, VarTypes, HeadVars, Goal, Proc). + proc_info_set_body(Proc0, VarSet, VarTypes, HeadVars, Goal, + TI_VarMap, TCI_VarMap, Proc). :- pred get_purity(hlds_goal, purity). :- mode get_purity(in, out) is det. diff --git a/compiler/code_util.m b/compiler/code_util.m index 2ae187724..9235fc323 100644 --- a/compiler/code_util.m +++ b/compiler/code_util.m @@ -746,7 +746,7 @@ code_util__cannot_stack_flush(GoalExpr - _) :- :- mode code_util__cannot_stack_flush_2(in) is semidet. code_util__cannot_stack_flush_2(unify(_, _, _, Unify, _)) :- - Unify \= complicated_unify(_, _). + Unify \= complicated_unify(_, _, _). code_util__cannot_stack_flush_2(call(_, _, _, BuiltinState, _, _)) :- BuiltinState = inline_builtin. code_util__cannot_stack_flush_2(conj(Goals)) :- diff --git a/compiler/dead_proc_elim.m b/compiler/dead_proc_elim.m index bd42c6b98..bbc812a2c 100644 --- a/compiler/dead_proc_elim.m +++ b/compiler/dead_proc_elim.m @@ -788,7 +788,7 @@ dead_pred_elim_analyze(DeadInfo0, DeadInfo) :- Needed, NeededNames), module_info_pred_info(ModuleInfo, PredId, PredInfo), pred_info_clauses_info(PredInfo, ClausesInfo), - ClausesInfo = clauses_info(_,_,_,_, Clauses), + clauses_info_clauses(ClausesInfo, Clauses), list__foldl(dead_pred_elim_process_clause, Clauses, DeadInfo1, DeadInfo2) ), diff --git a/compiler/dependency_graph.m b/compiler/dependency_graph.m index 9a2eb997c..de0c31971 100644 --- a/compiler/dependency_graph.m +++ b/compiler/dependency_graph.m @@ -10,6 +10,8 @@ % The dependency_graph records which procedures depend on which other % procedures. It is defined as a relation (see hlds_module.m) R where xRy % means that the definition of x depends on the definition of y. +% Note that imported procedures are not included in the dependency_graph +% (although opt_imported procedures are included). % % The other important structure is the dependency_ordering which is % a list of the cliques (strongly-connected components) of this relation, @@ -119,19 +121,14 @@ dependency_graph__add_pred_nodes([PredId | PredIds], ModuleInfo, DepGraph0, DepGraph) :- module_info_preds(ModuleInfo, PredTable), map__lookup(PredTable, PredId, PredInfo), - ( - % Don't bother adding nodes (or arcs) for predicates - % which which are imported (ie we don't have any `clauses' - % for). - pred_info_is_imported(PredInfo) - -> - DepGraph1 = DepGraph0 - ; - pred_info_procids(PredInfo, ProcIds), - dependency_graph__add_proc_nodes(ProcIds, PredId, ModuleInfo, - DepGraph0, DepGraph1) - ), - dependency_graph__add_pred_nodes(PredIds, ModuleInfo, DepGraph1, DepGraph). + % Don't bother adding nodes (or arcs) for procedures + % which which are imported (ie we don't have any `clauses' + % for). + pred_info_non_imported_procids(PredInfo, ProcIds), + dependency_graph__add_proc_nodes(ProcIds, PredId, ModuleInfo, + DepGraph0, DepGraph1), + dependency_graph__add_pred_nodes(PredIds, ModuleInfo, + DepGraph1, DepGraph). :- pred dependency_graph__add_proc_nodes(list(proc_id), pred_id, module_info, dependency_graph, dependency_graph). @@ -156,16 +153,11 @@ dependency_graph__add_pred_arcs([PredId | PredIds], ModuleInfo, DepGraph0, DepGraph) :- module_info_preds(ModuleInfo, PredTable), map__lookup(PredTable, PredId, PredInfo), - ( - pred_info_is_imported(PredInfo) - -> - DepGraph1 = DepGraph0 - ; - pred_info_procids(PredInfo, ProcIds), - dependency_graph__add_proc_arcs(ProcIds, PredId, ModuleInfo, - DepGraph0, DepGraph1) - ), - dependency_graph__add_pred_arcs(PredIds, ModuleInfo, DepGraph1, DepGraph). + pred_info_non_imported_procids(PredInfo, ProcIds), + dependency_graph__add_proc_arcs(ProcIds, PredId, ModuleInfo, + DepGraph0, DepGraph1), + dependency_graph__add_pred_arcs(PredIds, ModuleInfo, + DepGraph1, DepGraph). :- pred dependency_graph__add_proc_arcs(list(proc_id), pred_id, module_info, dependency_graph, dependency_graph). @@ -271,7 +263,7 @@ dependency_graph__add_arcs_in_goal_2(unify(_,_,_,Unify,_), Caller, ; Unify = deconstruct(_, Cons, _, _, _), dependency_graph__add_arcs_in_cons(Cons, Caller, DepGraph0, DepGraph) - ; Unify = complicated_unify(_, _), + ; Unify = complicated_unify(_, _, _), DepGraph0 = DepGraph ). diff --git a/compiler/det_analysis.m b/compiler/det_analysis.m index 3d0453176..bd8639990 100644 --- a/compiler/det_analysis.m +++ b/compiler/det_analysis.m @@ -1,5 +1,5 @@ %-----------------------------------------------------------------------------% -% Copyright (C) 1994-1998 The University of Melbourne. +% 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. %-----------------------------------------------------------------------------% @@ -925,7 +925,7 @@ det_infer_unify_examines_rep(assign(_, _), no). det_infer_unify_examines_rep(construct(_, _, _, _), no). det_infer_unify_examines_rep(deconstruct(_, _, _, _, _), yes). det_infer_unify_examines_rep(simple_test(_, _), yes). -det_infer_unify_examines_rep(complicated_unify(_, _), no). +det_infer_unify_examines_rep(complicated_unify(_, _, _), no). % Some complicated modes of complicated unifications _do_ % examine the representation... % but we will catch those by reporting errors in the @@ -949,7 +949,7 @@ det_infer_unify_canfail(deconstruct(_, _, _, _, CanFail), CanFail). det_infer_unify_canfail(assign(_, _), cannot_fail). det_infer_unify_canfail(construct(_, _, _, _), cannot_fail). det_infer_unify_canfail(simple_test(_, _), can_fail). -det_infer_unify_canfail(complicated_unify(_, CanFail), CanFail). +det_infer_unify_canfail(complicated_unify(_, CanFail, _), CanFail). %-----------------------------------------------------------------------------% diff --git a/compiler/det_report.m b/compiler/det_report.m index efef4371f..d075f341a 100644 --- a/compiler/det_report.m +++ b/compiler/det_report.m @@ -1,5 +1,5 @@ %-----------------------------------------------------------------------------% -% Copyright (C) 1995-1998 The University of Melbourne. +% Copyright (C) 1995-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. %-----------------------------------------------------------------------------% @@ -29,6 +29,8 @@ ; ite_cond_cannot_succeed(prog_context) ; negated_goal_cannot_fail(prog_context) ; negated_goal_cannot_succeed(prog_context) + ; goal_cannot_succeed(prog_context) + ; det_goal_has_no_outputs(prog_context) ; warn_obsolete(pred_id, prog_context) % warning about calls to predicates % for which there is a `:- pragma obsolete' @@ -997,7 +999,9 @@ det_msg_get_type(ite_cond_cannot_fail(_), simple_code_warning). det_msg_get_type(ite_cond_cannot_succeed(_), simple_code_warning). det_msg_get_type(negated_goal_cannot_fail(_), simple_code_warning). det_msg_get_type(negated_goal_cannot_succeed(_), simple_code_warning). - % XXX this isn't really a simple code warning. +det_msg_get_type(goal_cannot_succeed(_), simple_code_warning). +det_msg_get_type(det_goal_has_no_outputs(_), simple_code_warning). + % XXX warn_obsolete isn't really a simple code warning. % We should add a separate warning type for this. det_msg_get_type(warn_obsolete(_, _), simple_code_warning). det_msg_get_type(warn_infinite_recursion(_), simple_code_warning). @@ -1019,6 +1023,8 @@ det_msg_is_any_mode_msg(ite_cond_cannot_fail(_), all_modes). det_msg_is_any_mode_msg(ite_cond_cannot_succeed(_), all_modes). det_msg_is_any_mode_msg(negated_goal_cannot_fail(_), all_modes). det_msg_is_any_mode_msg(negated_goal_cannot_succeed(_), all_modes). +det_msg_is_any_mode_msg(goal_cannot_succeed(_), all_modes). +det_msg_is_any_mode_msg(det_goal_has_no_outputs(_), all_modes). det_msg_is_any_mode_msg(warn_obsolete(_, _), all_modes). det_msg_is_any_mode_msg(warn_infinite_recursion(_), any_mode). det_msg_is_any_mode_msg(duplicate_call(_, _, _), any_mode). @@ -1076,6 +1082,28 @@ det_report_msg(negated_goal_cannot_fail(Context), _) --> det_report_msg(negated_goal_cannot_succeed(Context), _) --> prog_out__write_context(Context), io__write_string("Warning: the negated goal cannot succeed.\n"). +det_report_msg(goal_cannot_succeed(Context), _) --> + prog_out__write_context(Context), + io__write_string("Warning: this goal cannot succeed.\n"), + globals__io_lookup_bool_option(verbose_errors, VerboseErrors), + ( { VerboseErrors = yes } -> + io__write_string( +"\tThe compiler will optimize away this goal, replacing it with `fail'. +\tTo disable this optimization, use the `--fully-strict' option.\n") + ; + [] + ). +det_report_msg(det_goal_has_no_outputs(Context), _) --> + prog_out__write_context(Context), + io__write_string("Warning: det goal has no outputs.\n"), + globals__io_lookup_bool_option(verbose_errors, VerboseErrors), + ( { VerboseErrors = yes } -> + io__write_string( +"\tThe compiler will optimize away this goal, replacing it with `true'. +\tTo disable this optimization, use the `--fully-strict' option.\n") + ; + [] + ). det_report_msg(warn_obsolete(PredId, Context), ModuleInfo) --> prog_out__write_context(Context), io__write_string("Warning: call to obsolete "), diff --git a/compiler/follow_code.m b/compiler/follow_code.m index fd69e5238..19d09b79d 100644 --- a/compiler/follow_code.m +++ b/compiler/follow_code.m @@ -1,5 +1,5 @@ %-----------------------------------------------------------------------------% -% Copyright (C) 1994-1998 The University of Melbourne. +% 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. %-----------------------------------------------------------------------------% @@ -312,7 +312,7 @@ check_follow_code_detism([_ - GoalInfo | Goals], Detism0) :- :- mode move_follow_code_is_builtin(in) is semidet. move_follow_code_is_builtin(unify(_, _, _, Unification, _) - _GoalInfo) :- - Unification \= complicated_unify(_, _). + Unification \= complicated_unify(_, _, _). move_follow_code_is_builtin(call(_, _, _, Builtin, _, _) - _GoalInfo) :- Builtin = inline_builtin. diff --git a/compiler/follow_vars.m b/compiler/follow_vars.m index 34d00b01d..99a9f7c3e 100644 --- a/compiler/follow_vars.m +++ b/compiler/follow_vars.m @@ -342,7 +342,7 @@ find_follow_vars_in_conj([Goal0 | Goals0], ModuleInfo, FollowVars0, BuiltinState = inline_builtin ; GoalExpr0 = unify(_, _, _, Unification, _), - Unification \= complicated_unify(_, _) + Unification \= complicated_unify(_, _, _) ) -> AttachToNext = no diff --git a/compiler/goal_util.m b/compiler/goal_util.m index 833a21f35..ca27d4894 100644 --- a/compiler/goal_util.m +++ b/compiler/goal_util.m @@ -414,8 +414,9 @@ goal_util__rename_unify(assign(L0, R0), Must, Subn, assign(L, R)) :- goal_util__rename_unify(simple_test(L0, R0), Must, Subn, simple_test(L, R)) :- goal_util__rename_var(L0, Must, Subn, L), goal_util__rename_var(R0, Must, Subn, R). -goal_util__rename_unify(complicated_unify(Modes, Cat), _Must, _Subn, - complicated_unify(Modes, Cat)). +goal_util__rename_unify(complicated_unify(Modes, Cat, TypeInfoVars), + _Must, _Subn, + complicated_unify(Modes, Cat, TypeInfoVars)). %-----------------------------------------------------------------------------% diff --git a/compiler/higher_order.m b/compiler/higher_order.m index f7d64e368..9ab215a22 100644 --- a/compiler/higher_order.m +++ b/compiler/higher_order.m @@ -607,7 +607,7 @@ check_unify(construct(LVar, ConsId, Args, _Modes), Info0, Info) :- Info = info(PredVars, Requests, NewPreds, PredProcId, PredInfo, ProcInfo, ModuleInfo, Params, Changed). -check_unify(complicated_unify(_, _)) --> +check_unify(complicated_unify(_, _, _)) --> { error("higher_order:check_unify - complicated unification") }. :- pred is_interesting_cons_id(ho_params::in, cons_id::in) is semidet. @@ -1748,11 +1748,13 @@ create_new_pred(Request, NewPred, NextHOid0, NextHOid, varset__init(EmptyVarSet), map__init(EmptyVarTypes), map__init(EmptyProofs), + map__init(EmptyTIMap), + map__init(EmptyTCIMap), % This isn't looked at after here, and just clutters up % hlds dumps if it's filled in. ClausesInfo = clauses_info(EmptyVarSet, EmptyVarTypes, - EmptyVarTypes, [], []), + EmptyVarTypes, [], [], EmptyTIMap, EmptyTCIMap), pred_info_init(PredModule, SymName, Arity, ArgTVarSet, ExistQVars, Types, true, Context, ClausesInfo, Status, MarkerList, GoalType, PredOrFunc, ClassContext, EmptyProofs, Owner, PredInfo1), diff --git a/compiler/hlds_goal.m b/compiler/hlds_goal.m index cebbf75e9..d03f49abd 100644 --- a/compiler/hlds_goal.m +++ b/compiler/hlds_goal.m @@ -310,7 +310,29 @@ ; complicated_unify( uni_mode, % The mode of the unification. - can_fail % Whether or not it could possibly fail + can_fail, % Whether or not it could possibly fail + + % When unifying polymorphic types such as + % map/2, we need to pass type_info variables + % to the unification procedure for map/2 + % so that it knows how to unify the + % polymorphically typed components of the + % data structure. Likewise for comparison + % predicates. + % This field records which type_info variables + % we will need. + % This field is set by polymorphism.m. + % It is used by quantification.m + % when recomputing the nonlocals. + % It is also used by modecheck_unify.m, + % which checks that the type_info + % variables needed are all ground. + % It is also checked by simplify.m when + % it converts complicated unifications + % into procedure calls. + list(prog_var) % The type_info variables needed + % by this unification, if it ends up + % being a complicated unify. ). % A unify_context describes the location in the original source diff --git a/compiler/hlds_out.m b/compiler/hlds_out.m index 5e300a2fd..ce4b2e362 100644 --- a/compiler/hlds_out.m +++ b/compiler/hlds_out.m @@ -542,7 +542,8 @@ hlds_out__write_pred(Indent, ModuleInfo, PredId, PredInfo) --> ; [] ), - { ClausesInfo = clauses_info(VarSet, _, VarTypes, HeadVars, Clauses) }, + { ClausesInfo = clauses_info(VarSet, _, VarTypes, HeadVars, Clauses, + TypeInfoMap, TypeClassInfoMap) }, ( { string__contains_char(Verbose, 'C') } -> hlds_out__write_indent(Indent), io__write_string("% pred id: "), @@ -561,6 +562,10 @@ hlds_out__write_pred(Indent, ModuleInfo, PredId, PredInfo) --> hlds_out__write_marker_list(MarkerList), io__write_string("\n") ), + hlds_out__write_typeinfo_varmap(Indent, AppendVarnums, + TypeInfoMap, VarSet, TVarSet), + hlds_out__write_typeclass_info_varmap(Indent, AppendVarnums, + TypeClassInfoMap, VarSet, TVarSet), ( { map__is_empty(Proofs) } -> [] ; @@ -568,6 +573,12 @@ hlds_out__write_pred(Indent, ModuleInfo, PredId, PredInfo) --> Proofs), io__write_string("\n") ), + + % XXX The indexes are not part of the clauses_info, + % so why is this code inside this if-then-else + % with the condition `string__contains_char(Verbose, 'C')'? + % Shouldn't it be dependent on a different letter? + ( { Indexes = [] } -> [] ; @@ -1262,9 +1273,11 @@ hlds_out__write_goal_2(unify(A, B, _, Unification, _), ModuleInfo, VarSet, ( % don't output bogus info if we haven't been through % mode analysis yet - { Unification = complicated_unify(Mode, CanFail) }, + { Unification = complicated_unify(Mode, CanFail, + TypeInfoVars) }, { CanFail = can_fail }, - { Mode = (free - free -> free - free) } + { Mode = (free - free -> free - free) }, + { TypeInfoVars = [] } -> [] ; @@ -1406,8 +1419,8 @@ hlds_out__write_unification(deconstruct(Var, ConsId, ArgVars, ArgModes, !, hlds_out_write_functor_and_submodes(ConsId, ArgVars, ArgModes, ModuleInfo, ProgVarSet, InstVarSet, AppendVarnums, Indent). -hlds_out__write_unification(complicated_unify(Mode, CanFail), - _ModuleInfo, _ProgVarSet, InstVarSet, _, Indent) --> +hlds_out__write_unification(complicated_unify(Mode, CanFail, TypeInfoVars), + _ModuleInfo, ProgVarSet, InstVarSet, AppendVarNums, Indent) --> hlds_out__write_indent(Indent), io__write_string("% "), ( { CanFail = can_fail }, @@ -1418,8 +1431,13 @@ hlds_out__write_unification(complicated_unify(Mode, CanFail), !, io__write_string("mode: "), mercury_output_uni_mode(Mode, InstVarSet), + io__write_string("\n"), + hlds_out__write_indent(Indent), + io__write_string("% type-info vars: "), + mercury_output_vars(TypeInfoVars, ProgVarSet, AppendVarNums), io__write_string("\n"). + :- pred hlds_out_write_functor_and_submodes(cons_id, list(prog_var), list(uni_mode), module_info, prog_varset, inst_varset, bool, int, io__state, io__state). diff --git a/compiler/hlds_pred.m b/compiler/hlds_pred.m index c17b3776b..b982c08a4 100644 --- a/compiler/hlds_pred.m +++ b/compiler/hlds_pred.m @@ -81,6 +81,8 @@ :- type pred_proc_id ---> proc(pred_id, proc_id). :- type pred_proc_list == list(pred_proc_id). +%-----------------------------------------------------------------------------% + % The clauses_info structure contains the clauses for a predicate % after conversion from the item_list by make_hlds.m. % Typechecking is performed on the clauses info, then the clauses @@ -97,9 +99,70 @@ % variable types % inferred by typecheck.m. list(prog_var), % head vars - list(clause) + list(clause), + % the following two fields + % are computed by + % polymorphism.m + type_info_varmap, + typeclass_info_varmap ). +:- pred clauses_info_varset(clauses_info, prog_varset). +:- mode clauses_info_varset(in, out) is det. + + % This partial map holds the types specified by any explicit + % type qualifiers in the clauses. +:- pred clauses_info_explicit_vartypes(clauses_info, map(prog_var, type)). +:- mode clauses_info_explicit_vartypes(in, out) is det. + + % This map contains the types of all the variables, as inferred + % by typecheck.m. +:- pred clauses_info_vartypes(clauses_info, map(prog_var, type)). +:- mode clauses_info_vartypes(in, out) is det. + +:- pred clauses_info_type_info_varmap(clauses_info, type_info_varmap). +:- mode clauses_info_type_info_varmap(in, out) is det. + +:- pred clauses_info_typeclass_info_varmap(clauses_info, + typeclass_info_varmap). +:- mode clauses_info_typeclass_info_varmap(in, out) is det. + +:- pred clauses_info_headvars(clauses_info, list(prog_var)). +:- mode clauses_info_headvars(in, out) is det. + +:- pred clauses_info_clauses(clauses_info, list(clause)). +:- mode clauses_info_clauses(in, out) is det. + +:- pred clauses_info_set_headvars(clauses_info, list(prog_var), clauses_info). +:- mode clauses_info_set_headvars(in, in, out) is det. + +:- pred clauses_info_set_clauses(clauses_info, list(clause), clauses_info). +:- mode clauses_info_set_clauses(in, in, out) is det. + +:- pred clauses_info_set_varset(clauses_info, prog_varset, clauses_info). +:- mode clauses_info_set_varset(in, in, out) is det. + + % This partial map holds the types specified by any explicit + % type qualifiers in the clauses. +:- pred clauses_info_set_explicit_vartypes(clauses_info, map(prog_var, type), + clauses_info). +:- mode clauses_info_set_explicit_vartypes(in, in, out) is det. + + % This map contains the types of all the variables, as inferred + % by typecheck.m. +:- pred clauses_info_set_vartypes(clauses_info, map(prog_var, type), + clauses_info). +:- mode clauses_info_set_vartypes(in, in, out) is det. + +:- pred clauses_info_set_type_info_varmap(clauses_info, type_info_varmap, + clauses_info). +:- mode clauses_info_set_type_info_varmap(in, in, out) is det. + +:- pred clauses_info_set_typeclass_info_varmap(clauses_info, + typeclass_info_varmap, clauses_info). +:- mode clauses_info_set_typeclass_info_varmap(in, in, out) is det. + + :- type clause ---> clause( list(proc_id), % modes for which % this clause applies @@ -110,6 +173,8 @@ prog_context ). +%-----------------------------------------------------------------------------% + % The type of goals that have been given for a pred. :- type goal_type ---> pragmas % pragma c_code(...) @@ -320,6 +385,22 @@ % module, name and arity. :- type aditi_owner == string. + % The constraint_proof_map is a map which for each type class + % constraint records how/why that constraint was satisfied. + % This information is used to determine how to construct the + % typeclass_info for that constraint. +:- type constraint_proof_map == map(class_constraint, constraint_proof). + + % A typeclass_info_varmap is a map which for each type class constraint + % records which variable contains the typeclass_info for that + % constraint. +:- type typeclass_info_varmap == map(class_constraint, prog_var). + + % A type_info_varmap is a map which for each type variable + % records where the type_info for that type variable is stored. +:- type type_info_varmap == map(tvar, type_info_locn). + + % A type_info_locn specifies how to access a type_info. :- type type_info_locn ---> type_info(prog_var) % It is a normal type_info, i.e. the type @@ -359,10 +440,9 @@ % which were added to the front of the argument list. :- pred hlds_pred__define_new_pred(hlds_goal, hlds_goal, list(prog_var), list(prog_var), instmap, string, tvarset, map(prog_var, type), - class_constraints, map(tvar, type_info_locn), - map(class_constraint, prog_var), prog_varset, pred_markers, - aditi_owner, is_address_taken, module_info, module_info, - pred_proc_id). + class_constraints, type_info_varmap, typeclass_info_varmap, + prog_varset, pred_markers, aditi_owner, is_address_taken, + module_info, module_info, pred_proc_id). :- mode hlds_pred__define_new_pred(in, out, in, out, in, in, in, in, in, in, in, in, in, in, in, in, out, out) is det. @@ -372,7 +452,7 @@ :- pred pred_info_init(module_name, sym_name, arity, tvarset, existq_tvars, list(type), condition, prog_context, clauses_info, import_status, pred_markers, goal_type, pred_or_func, class_constraints, - map(class_constraint, constraint_proof), aditi_owner, pred_info). + constraint_proof_map, aditi_owner, pred_info). :- mode pred_info_init(in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, out) is det. @@ -518,12 +598,11 @@ :- pred pred_info_set_class_context(pred_info, class_constraints, pred_info). :- mode pred_info_set_class_context(in, in, out) is det. -:- pred pred_info_get_constraint_proofs(pred_info, - map(class_constraint, constraint_proof)). +:- pred pred_info_get_constraint_proofs(pred_info, constraint_proof_map). :- mode pred_info_get_constraint_proofs(in, out) is det. -:- pred pred_info_set_constraint_proofs(pred_info, - map(class_constraint, constraint_proof), pred_info). +:- pred pred_info_set_constraint_proofs(pred_info, constraint_proof_map, + pred_info). :- mode pred_info_set_constraint_proofs(in, in, out) is det. :- pred pred_info_get_aditi_owner(pred_info, string). @@ -667,7 +746,7 @@ status_defined_in_this_module(local, yes). % the class constraints on the % type variables in the predicate's % type declaration - map(class_constraint, constraint_proof), + constraint_proof_map, % explanations of how redundant % constraints were eliminated. These % are needed by polymorphism.m to @@ -734,9 +813,13 @@ pred_info_create(ModuleName, SymName, TypeVarSet, ExistQVars, Types, Cond, proc_info_varset(ProcInfo, VarSet), proc_info_vartypes(ProcInfo, VarTypes), proc_info_headvars(ProcInfo, HeadVars), + proc_info_typeinfo_varmap(ProcInfo, TypeInfoMap), + proc_info_typeclass_info_varmap(ProcInfo, TypeClassInfoMap), unqualify_name(SymName, PredName), % The empty list of clauses is a little white lie. - ClausesInfo = clauses_info(VarSet, VarTypes, VarTypes, HeadVars, []), + Clauses = [], + ClausesInfo = clauses_info(VarSet, VarTypes, VarTypes, HeadVars, + Clauses, TypeInfoMap, TypeClassInfoMap), map__init(ClassProofs), term__vars_list(Types, TVars), list__delete_elems(TVars, ExistQVars, HeadTypeParams), @@ -1040,6 +1123,49 @@ marker_list_to_markers(Markers, Markers). %-----------------------------------------------------------------------------% +% :- type clauses_info ---> clauses_info( +% prog_varset, % variable names +% map(prog_var, type), +% % variable types from +% % explicit qualifications +% map(prog_var, type), +% % variable types +% % inferred by typecheck.m. +% list(prog_var), % head vars +% list(clause), +% type_info_varmap, +% typeclass_info_varmap, +% ). + +clauses_info_varset(clauses_info(VarSet, _, _, _, _, _, _), VarSet). +clauses_info_explicit_vartypes( + clauses_info(_, ExplicitVarTypes, _, _, _, _, _), ExplicitVarTypes). +clauses_info_vartypes(clauses_info(_, _, VarTypes, _, _, _, _), VarTypes). +clauses_info_headvars(clauses_info(_, _, _, HeadVars, _, _, _), HeadVars). +clauses_info_clauses(clauses_info(_, _, _, _, Clauses, _, _), Clauses). +clauses_info_type_info_varmap(clauses_info(_, _, _, _, _, TIMap, _), TIMap). +clauses_info_typeclass_info_varmap(clauses_info(_, _, _, _, _, _, TCIMap), + TCIMap). + +clauses_info_set_varset(clauses_info(_, B, C, D, E, F, G), VarSet, + clauses_info(VarSet, B, C, D, E, F, G)). +clauses_info_set_explicit_vartypes(clauses_info(A, _, C, D, E, F, G), + ExplicitVarTypes, + clauses_info(A, ExplicitVarTypes, C, D, E, F, G)). +clauses_info_set_vartypes(clauses_info(A, B, _, D, E, F, G), VarTypes, + clauses_info(A, B, VarTypes, D, E, F, G)). +clauses_info_set_headvars(clauses_info(A, B, C, _, E, F, G), HeadVars, + clauses_info(A, B, C, HeadVars, E, F, G)). +clauses_info_set_clauses(clauses_info(A, B, C, D, _, F, G), Clauses, + clauses_info(A, B, C, D, Clauses, F, G)). +clauses_info_set_type_info_varmap(clauses_info(A, B, C, D, E, _, G), TIMap, + clauses_info(A, B, C, D, E, TIMap, G)). +clauses_info_set_typeclass_info_varmap(clauses_info(A, B, C, D, E, F, _), + TCIMap, + clauses_info(A, B, C, D, E, F, TCIMap)). + +%-----------------------------------------------------------------------------% + hlds_pred__define_new_pred(Goal0, Goal, ArgVars0, ExtraTypeInfos, InstMap0, PredName, TVarSet, VarTypes0, ClassContext, TVarMap, TCVarMap, VarSet0, Markers, Owner, IsAddressTaken, @@ -1143,21 +1269,21 @@ compute_arg_types_modes([Var | Vars], VarTypes, InstMap0, InstMap, :- pred proc_info_set(maybe(determinism), prog_varset, map(prog_var, type), list(prog_var), list(mode), maybe(list(is_live)), hlds_goal, prog_context, stack_slots, determinism, bool, list(arg_info), - liveness_info, map(tvar, type_info_locn), - map(class_constraint, prog_var), maybe(arg_size_info), - maybe(termination_info), is_address_taken, proc_info). + liveness_info, type_info_varmap, typeclass_info_varmap, + maybe(arg_size_info), maybe(termination_info), is_address_taken, + proc_info). :- mode proc_info_set(in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, in, out) is det. :- pred proc_info_create(prog_varset, map(prog_var, type), list(prog_var), list(mode), determinism, hlds_goal, prog_context, - map(tvar, type_info_locn), map(class_constraint, prog_var), - is_address_taken, proc_info). + type_info_varmap, typeclass_info_varmap, is_address_taken, proc_info). :- mode proc_info_create(in, in, in, in, in, in, in, in, in, in, out) is det. :- pred proc_info_set_body(proc_info, prog_varset, map(prog_var, type), - list(prog_var), hlds_goal, proc_info). -:- mode proc_info_set_body(in, in, in, in, in, out) is det. + list(prog_var), hlds_goal, type_info_varmap, + typeclass_info_varmap, proc_info). +:- mode proc_info_set_body(in, in, in, in, in, in, in, out) is det. :- pred proc_info_declared_determinism(proc_info, maybe(determinism)). :- mode proc_info_declared_determinism(in, out) is det. @@ -1266,11 +1392,10 @@ compute_arg_types_modes([Var | Vars], VarTypes, InstMap0, InstMap, :- pred proc_info_set_can_process(proc_info, bool, proc_info). :- mode proc_info_set_can_process(in, in, out) is det. -:- pred proc_info_typeinfo_varmap(proc_info, map(tvar, type_info_locn)). +:- pred proc_info_typeinfo_varmap(proc_info, type_info_varmap). :- mode proc_info_typeinfo_varmap(in, out) is det. -:- pred proc_info_set_typeinfo_varmap(proc_info, map(tvar, type_info_locn), - proc_info). +:- pred proc_info_set_typeinfo_varmap(proc_info, type_info_varmap, proc_info). :- mode proc_info_set_typeinfo_varmap(in, in, out) is det. :- pred proc_info_eval_method(proc_info, eval_method). @@ -1279,12 +1404,11 @@ compute_arg_types_modes([Var | Vars], VarTypes, InstMap0, InstMap, :- pred proc_info_set_eval_method(proc_info, eval_method, proc_info). :- mode proc_info_set_eval_method(in, in, out) is det. -:- pred proc_info_typeclass_info_varmap(proc_info, - map(class_constraint, prog_var)). +:- pred proc_info_typeclass_info_varmap(proc_info, typeclass_info_varmap). :- mode proc_info_typeclass_info_varmap(in, out) is det. -:- pred proc_info_set_typeclass_info_varmap(proc_info, - map(class_constraint, prog_var), proc_info). +:- pred proc_info_set_typeclass_info_varmap(proc_info, typeclass_info_varmap, + proc_info). :- mode proc_info_set_typeclass_info_varmap(in, in, out) is det. :- pred proc_info_maybe_declared_argmodes(proc_info, maybe(list(mode))). @@ -1355,10 +1479,9 @@ compute_arg_types_modes([Var | Vars], VarTypes, InstMap0, InstMap, % should be passed. liveness_info, % the initial liveness, % for code generation - map(tvar, type_info_locn), - % typeinfo vars for - % type parameters - map(class_constraint, prog_var), + type_info_varmap, + % typeinfo vars for type parameters + typeclass_info_varmap, % typeclass_info vars for class % constraints eval_method, % how should the proc be evaluated @@ -1430,11 +1553,12 @@ proc_info_create(VarSet, VarTypes, HeadVars, HeadModes, Detism, Goal, Liveness, TVarMap, TCVarsMap, eval_normal, no, no, no, IsAddressTaken). -proc_info_set_body(ProcInfo0, VarSet, VarTypes, HeadVars, Goal, ProcInfo) :- +proc_info_set_body(ProcInfo0, VarSet, VarTypes, HeadVars, Goal, + TI_VarMap, TCI_VarMap, ProcInfo) :- ProcInfo0 = procedure(A, _, _, _, E, F, _, - H, I, J, K, L, M, N, O, P, Q, R, S, T), + H, I, J, K, L, M, _, _, P, Q, R, S, T), ProcInfo = procedure(A, VarSet, VarTypes, HeadVars, E, F, Goal, - H, I, J, K, L, M, N, O, P, Q, R, S, T). + H, I, J, K, L, M, TI_VarMap, TCI_VarMap, P, Q, R, S, T). proc_info_interface_determinism(ProcInfo, Determinism) :- proc_info_declared_determinism(ProcInfo, MaybeDeterminism), @@ -1602,10 +1726,9 @@ proc_info_is_address_taken(ProcInfo, T) :- % % should be passed. % M liveness_info, % the initial liveness, % % for code generation -% N map(tvar, type_info_locn), -% % typeinfo vars for -% % type parameters -% O map(class_constraint, var), +% N type_info_varmap, +% % typeinfo vars for type parameters +% O typeclass_info_varmap, % % typeclass_info vars for class % % constraints % P eval_method, diff --git a/compiler/intermod.m b/compiler/intermod.m index 4f64beae5..0147302e3 100644 --- a/compiler/intermod.m +++ b/compiler/intermod.m @@ -217,14 +217,14 @@ intermod__gather_preds([PredId | PredIds], CollectTypes, -> { pred_info_clauses_info(PredInfo0, ClausesInfo0) }, { pred_info_typevarset(PredInfo0, TVarSet) }, - { ClausesInfo0 = clauses_info(VarSet, DeclTypes, VarTypes, - HeadVars, Clauses0) }, + { clauses_info_vartypes(ClausesInfo0, VarTypes) }, + { clauses_info_clauses(ClausesInfo0, Clauses0) }, intermod_info_set_var_types(VarTypes), intermod_info_set_tvarset(TVarSet), intermod__traverse_clauses(Clauses0, Clauses, DoWrite), ( { DoWrite = yes } -> - { ClausesInfo = clauses_info(VarSet, DeclTypes, - VarTypes, HeadVars, Clauses) }, + { clauses_info_set_clauses(ClausesInfo0, Clauses, + ClausesInfo) }, { pred_info_set_clauses_info(PredInfo0, ClausesInfo, PredInfo) }, { map__det_update(PredTable0, PredId, @@ -1064,15 +1064,18 @@ intermod__write_preds(ModuleInfo, [PredId | PredIds]) --> % already be in the interface file. { pred_info_clauses_info(PredInfo, ClausesInfo) }, - { ClausesInfo = clauses_info(Varset, _, _VarTypes, HeadVars, Clauses) }, + { clauses_info_varset(ClausesInfo, VarSet) }, + { clauses_info_headvars(ClausesInfo, HeadVars) }, + { clauses_info_clauses(ClausesInfo, Clauses) }, + % handle pragma c_code(...) separately ( { pred_info_get_goal_type(PredInfo, pragmas) } -> { pred_info_procedures(PredInfo, Procs) }, - intermod__write_c_code(SymName, PredOrFunc, HeadVars, Varset, + intermod__write_c_code(SymName, PredOrFunc, HeadVars, VarSet, Clauses, Procs) ; % { pred_info_typevarset(PredInfo, TVarSet) }, - hlds_out__write_clauses(1, ModuleInfo, PredId, Varset, no, + hlds_out__write_clauses(1, ModuleInfo, PredId, VarSet, no, HeadVars, PredOrFunc, Clauses, no) % HeadVars, Clauses, yes(TVarSet, VarTypes)) ), diff --git a/compiler/lambda.m b/compiler/lambda.m index 2d57e3302..3ce320e6b 100644 --- a/compiler/lambda.m +++ b/compiler/lambda.m @@ -72,6 +72,9 @@ :- import_module hlds_module, hlds_pred, hlds_goal, hlds_data, prog_data. :- import_module list, map, set. +:- pred lambda__process_module(module_info, module_info). +:- mode lambda__process_module(in, out) is det. + :- pred lambda__process_pred(pred_id, module_info, module_info). :- mode lambda__process_pred(in, in, out) is det. @@ -89,7 +92,7 @@ :- implementation. -:- import_module make_hlds, globals, options, term, varset. +:- import_module make_hlds, globals, options, term, varset, type_util. :- import_module goal_util, prog_util, mode_util, inst_match, llds, arg_info. :- import_module bool, string, std_util, require. @@ -117,6 +120,20 @@ % This whole section just traverses the module structure. +lambda__process_module(ModuleInfo0, ModuleInfo) :- + module_info_predids(ModuleInfo0, PredIds), + lambda__process_preds(PredIds, ModuleInfo0, ModuleInfo1), + % Need update the dependency graph to include the lambda predicates. + module_info_clobber_dependency_info(ModuleInfo1, ModuleInfo). + +:- pred lambda__process_preds(list(pred_id), module_info, module_info). +:- mode lambda__process_preds(in, in, out) is det. + +lambda__process_preds([], ModuleInfo, ModuleInfo). +lambda__process_preds([PredId | PredIds], ModuleInfo0, ModuleInfo) :- + lambda__process_pred(PredId, ModuleInfo0, ModuleInfo1), + lambda__process_preds(PredIds, ModuleInfo1, ModuleInfo). + lambda__process_pred(PredId, ModuleInfo0, ModuleInfo) :- module_info_pred_info(ModuleInfo0, PredId, PredInfo), pred_info_procids(PredInfo, ProcIds), @@ -200,10 +217,13 @@ lambda__process_goal_2(unify(XVar, Y, Mode, Unification, Context), GoalInfo, Unify - GoalInfo) --> ( { Y = lambda_goal(PredOrFunc, NonLocalVars, Vars, Modes, Det, LambdaGoal0) } -> - % for lambda expressions, we must convert the lambda expression - % into a new predicate + % first, process the lambda goal recursively, in case it + % contains some nested lambda expressions. + lambda__process_goal(LambdaGoal0, LambdaGoal1), + + % then, convert the lambda expression into a new predicate lambda__process_lambda(PredOrFunc, Vars, Modes, Det, - NonLocalVars, LambdaGoal0, + NonLocalVars, LambdaGoal1, Unification, Y1, Unification1), { Unify = unify(XVar, Y1, Mode, Unification1, Context) } ; @@ -274,9 +294,22 @@ lambda__process_cases([case(ConsId, Goal0) | Cases0], lambda__process_lambda(PredOrFunc, Vars, Modes, Det, OrigNonLocals0, LambdaGoal, Unification0, Functor, Unification, LambdaInfo0, LambdaInfo) :- - LambdaInfo0 = lambda_info(VarSet, VarTypes, Constraints, TVarSet, + LambdaInfo0 = lambda_info(VarSet, VarTypes, _PredConstraints, TVarSet, TVarMap, TCVarMap, Markers, POF, PredName, Owner, ModuleInfo0), - % XXX existentially typed lambda expressions are not yet supported + + % Calculate the constraints which apply to this lambda + % expression. + % Note currently we only allow lambda expressions + % to have universally quantified constraints. + map__keys(TCVarMap, AllConstraints), + map__apply_to_list(Vars, VarTypes, LambdaVarTypes), + list__map(type_util__vars, LambdaVarTypes, LambdaTypeVarsList), + list__condense(LambdaTypeVarsList, LambdaTypeVars), + list__filter(lambda__constraint_contains_vars(LambdaTypeVars), + AllConstraints, UnivConstraints), + Constraints = constraints(UnivConstraints, []), + + % existentially typed lambda expressions are not yet supported % (see the documentation at top of this file) ExistQVars = [], LambdaGoal = _ - LambdaGoalInfo, @@ -290,6 +323,19 @@ lambda__process_lambda(PredOrFunc, Vars, Modes, Det, OrigNonLocals0, LambdaGoal, LambdaInfo = lambda_info(VarSet, VarTypes, Constraints, TVarSet, TVarMap, TCVarMap, Markers, POF, PredName, Owner, ModuleInfo). +:- pred lambda__constraint_contains_vars(list(tvar), class_constraint). +:- mode lambda__constraint_contains_vars(in, in) is semidet. + +lambda__constraint_contains_vars(LambdaVars, ClassConstraint) :- + ClassConstraint = constraint(_, ConstraintTypes), + list__map(type_util__vars, ConstraintTypes, ConstraintVarsList), + list__condense(ConstraintVarsList, ConstraintVars), + % Probably not the most efficient way of doing it, but I + % wouldn't think that it matters. + set__list_to_set(LambdaVars, LambdaVarsSet), + set__list_to_set(ConstraintVars, ConstraintVarsSet), + set__subset(ConstraintVarsSet, LambdaVarsSet). + lambda__transform_lambda(PredOrFunc, OrigPredName, Vars, Modes, Detism, OrigVars, ExtraTypeInfos, LambdaGoal, Unification0, VarSet, VarTypes, Constraints, TVarSet, TVarMap, TCVarMap, @@ -301,7 +347,7 @@ lambda__transform_lambda(PredOrFunc, OrigPredName, Vars, Modes, Detism, Var = Var0, UniModes1 = UniModes0 ; - error("polymorphism__transform_lambda: weird unification") + error("lambda__transform_lambda: weird unification") ), % Optimize a special case: replace diff --git a/compiler/live_vars.m b/compiler/live_vars.m index d17abc639..e7e031761 100644 --- a/compiler/live_vars.m +++ b/compiler/live_vars.m @@ -359,7 +359,7 @@ build_live_sets_in_goal_2(call(PredId, ProcId, ArgVars, BuiltinState, _, _), build_live_sets_in_goal_2(unify(_,_,_,D,_), Liveness, ResumeVars0, LiveSets0, _, _, _, Liveness, ResumeVars0, LiveSets) :- ( - D = complicated_unify(_, _) + D = complicated_unify(_, _, _) -> % we have to save all live and protected variables % across complicated unifications. diff --git a/compiler/magic.m b/compiler/magic.m index 796ec75c9..7129f1bd9 100644 --- a/compiler/magic.m +++ b/compiler/magic.m @@ -1216,7 +1216,7 @@ magic__interface_pred_info(CPredProcId, PredProcId, magic__make_type_info_vars(Types, TypeInfoVars, TypeInfoGoals, PredInfo0, PredInfo, ProcInfo0, ProcInfo) --> magic_info_get_module_info(ModuleInfo0), - { init_poly_info(ModuleInfo0, PredInfo0, ProcInfo0, PolyInfo0) }, + { create_poly_info(ModuleInfo0, PredInfo0, ProcInfo0, PolyInfo0) }, { ExistQVars = [] }, { term__context_init(Context) }, { polymorphism__make_type_info_vars(Types, ExistQVars, Context, diff --git a/compiler/make_hlds.m b/compiler/make_hlds.m index 4f0f2281e..e27c78db2 100644 --- a/compiler/make_hlds.m +++ b/compiler/make_hlds.m @@ -856,8 +856,10 @@ add_pragma_type_spec_2(Pragma, SymName, SpecName, Arity, Goal = call(PredId, DummyProcId, Args, not_builtin, no, SymName) - GoalInfo, Clause = clause(ProcIds, Goal, Context), + map__init(TI_VarMap), + map__init(TCI_VarMap), Clauses = clauses_info(ArgVarSet, VarTypes0, - VarTypes0, Args, [Clause]), + VarTypes0, Args, [Clause], TI_VarMap, TCI_VarMap), pred_info_get_markers(PredInfo0, Markers), map__init(Proofs), ( pred_info_is_imported(PredInfo0) -> @@ -2357,8 +2359,8 @@ add_builtin(PredId, Types, PredInfo0, PredInfo) :- pred_info_name(PredInfo0, Name), pred_info_context(PredInfo0, Context), pred_info_clauses_info(PredInfo0, ClausesInfo0), - ClausesInfo0 = clauses_info(VarSet, _VarTypes0, _VarTypes1, - HeadVars, _ClauseList0), + clauses_info_varset(ClausesInfo0, VarSet), + clauses_info_headvars(ClausesInfo0, HeadVars), % % construct the pseudo-recursive call to Module:Name(HeadVars) @@ -2385,8 +2387,10 @@ add_builtin(PredId, Types, PredInfo0, PredInfo) :- % ClauseList = [Clause], map__from_corresponding_lists(HeadVars, Types, VarTypes), + map__init(TI_VarMap), + map__init(TCI_VarMap), ClausesInfo = clauses_info(VarSet, VarTypes, VarTypes, - HeadVars, ClauseList), + HeadVars, ClauseList, TI_VarMap, TCI_VarMap), pred_info_set_clauses_info(PredInfo0, ClausesInfo, PredInfo). %-----------------------------------------------------------------------------% @@ -4177,7 +4181,10 @@ clauses_info_init(Arity, ClausesInfo) :- map__init(VarTypes), varset__init(VarSet0), make_n_fresh_vars("HeadVar__", Arity, VarSet0, HeadVars, VarSet), - ClausesInfo = clauses_info(VarSet, VarTypes, VarTypes, HeadVars, []). + map__init(TI_VarMap), + map__init(TCI_VarMap), + ClausesInfo = clauses_info(VarSet, VarTypes, VarTypes, HeadVars, [], + TI_VarMap, TCI_VarMap). :- pred clauses_info_add_clause(clauses_info::in, pred_id::in, list(proc_id)::in, prog_varset::in, tvarset::in, @@ -4190,7 +4197,8 @@ clauses_info_add_clause(ClausesInfo0, PredId, ModeIds, CVarSet, TVarSet0, Args, Body, Context, Goal, VarSet, TVarSet0, ClausesInfo, Warnings, Info0, Info) --> { ClausesInfo0 = clauses_info(VarSet0, VarTypes0, VarTypes1, - HeadVars, ClauseList0) }, + HeadVars, ClauseList0, + TI_VarMap, TCI_VarMap) }, { update_qual_info(Info0, TVarSet0, VarTypes0, PredId, Info1) }, { varset__merge_subst(VarSet0, CVarSet, VarSet1, Subst) }, transform(Subst, HeadVars, Args, Body, VarSet1, Context, @@ -4200,7 +4208,8 @@ clauses_info_add_clause(ClausesInfo0, PredId, ModeIds, CVarSet, TVarSet0, ClauseList) }, { qual_info_get_var_types(Info, VarTypes) }, { ClausesInfo = clauses_info(VarSet, VarTypes, VarTypes1, - HeadVars, ClauseList) }. + HeadVars, ClauseList, + TI_VarMap, TCI_VarMap) }. %----------------------------------------------------------------------------- @@ -4221,7 +4230,7 @@ clauses_info_add_pragma_c_code(ClausesInfo0, Purity, Attributes, PredId, ClausesInfo, Info0, Info) --> { ClausesInfo0 = clauses_info(VarSet0, VarTypes, VarTypes1, - HeadVars, ClauseList), + HeadVars, ClauseList, TI_VarMap, TCI_VarMap), pragma_get_vars(PVars, Args0), pragma_get_var_infos(PVars, ArgInfo), @@ -4250,7 +4259,7 @@ clauses_info_add_pragma_c_code(ClausesInfo0, Purity, Attributes, PredId, HldsGoal, VarSet, _, _Warnings), NewClause = clause([ModeId], HldsGoal, Context), ClausesInfo = clauses_info(VarSet, VarTypes, VarTypes1, HeadVars, - [NewClause|ClauseList]) + [NewClause|ClauseList], TI_VarMap, TCI_VarMap) }. :- pred allocate_vars_for_saved_vars(list(string), list(pair(prog_var, string)), @@ -5023,7 +5032,7 @@ create_atomic_unification(A, B, Context, UnifyMainContext, UnifySubContext, Goal) :- UMode = ((free - free) -> (free - free)), Mode = ((free -> free) - (free -> free)), - UnifyInfo = complicated_unify(UMode, can_fail), + UnifyInfo = complicated_unify(UMode, can_fail, []), UnifyC = unify_context(UnifyMainContext, UnifySubContext), goal_info_init(GoalInfo0), goal_info_set_context(GoalInfo0, Context, GoalInfo), diff --git a/compiler/mercury_compile.m b/compiler/mercury_compile.m index f4350717e..5d84f9172 100644 --- a/compiler/mercury_compile.m +++ b/compiler/mercury_compile.m @@ -30,12 +30,12 @@ % the main compiler passes (mostly in order of execution) :- import_module handle_options, prog_io, prog_out, modules, module_qual. -:- import_module equiv_type, make_hlds, typecheck, purity, modes. +:- import_module equiv_type, make_hlds, typecheck, purity, polymorphism, modes. :- import_module switch_detection, cse_detection, det_analysis, unique_modes. :- import_module stratify, check_typeclass, simplify, intermod, trans_opt. :- import_module table_gen. :- import_module bytecode_gen, bytecode. -:- import_module (lambda), polymorphism, termination, higher_order, inlining. +:- import_module (lambda), termination, higher_order, inlining. :- import_module deforest, dnf, unused_args, magic, dead_proc_elim. :- import_module accumulator, lco, saved_vars, liveness. :- import_module follow_code, live_vars, arg_info, store_alloc, goal_path. @@ -388,12 +388,8 @@ mercury_compile(Module) --> % the appropriate warnings globals__io_lookup_bool_option(warn_unused_args, UnusedArgs), ( { UnusedArgs = yes } -> - % Run polymorphism so that the unused argument numbers - % read in from `.opt' files are correct. - mercury_compile__maybe_polymorphism(HLDS21, - Verbose, Stats, HLDS22), globals__io_set_option(optimize_unused_args, bool(no)), - mercury_compile__maybe_unused_args(HLDS22, + mercury_compile__maybe_unused_args(HLDS21, Verbose, Stats, _) ; [] @@ -717,7 +713,17 @@ mercury_compile__frontend_pass(HLDS1, HLDS, FoundUndefTypeError, { HLDS = HLDS4 }, { bool__or(FoundTypeError, FoundTypeclassError, FoundError) } - ; + ; { FoundTypeError = yes } -> + % + % XXX it would be nice if we could go on and mode-check + % the predicates which didn't have type errors, but + % we need to run polymorphism before running mode + % analysis, and currently polymorphism may get internal + % errors if any of the predicates are not type-correct. + % + { HLDS = HLDS4 }, + { FoundError = yes } + ; % only write out the `.opt' file if there are no type errors % or undefined modes ( { FoundTypeError = no, FoundUndefModeError = no } -> @@ -764,27 +770,25 @@ mercury_compile__maybe_write_optfile(MakeOptInt, HLDS0, HLDS) --> ( { MakeOptInt = yes } -> intermod__write_optfile(HLDS0, HLDS1), - % If intermod_unused_args is being performed, run mode and - % determinism analysis and polymorphism, then run unused_args + % If intermod_unused_args is being performed, run polymorphism, + % mode analysis and determinism analysis, then run unused_args % to append the unused argument information to the `.opt.tmp' % file written above. ( { IntermodArgs = yes ; Termination = yes } -> mercury_compile__frontend_pass_2_by_phases( HLDS1, HLDS2, FoundModeError), ( { FoundModeError = no } -> - mercury_compile__maybe_polymorphism(HLDS2, - Verbose, Stats, HLDS3), ( { IntermodArgs = yes } -> mercury_compile__maybe_unused_args( - HLDS3, Verbose, Stats, HLDS4) + HLDS2, Verbose, Stats, HLDS3) ; - { HLDS4 = HLDS3 } + { HLDS3 = HLDS2 } ), ( { Termination = yes } -> mercury_compile__maybe_termination( - HLDS4, Verbose, Stats, HLDS) + HLDS3, Verbose, Stats, HLDS) ; - { HLDS = HLDS4 } + { HLDS = HLDS3 } ) ; @@ -835,10 +839,7 @@ mercury_compile__output_trans_opt_file(HLDS25) --> globals__io_lookup_bool_option(verbose, Verbose), globals__io_lookup_bool_option(statistics, Stats), - mercury_compile__maybe_polymorphism(HLDS25, Verbose, Stats, HLDS26), - mercury_compile__maybe_dump_hlds(HLDS26, "26", "polymorphism"), !, - - mercury_compile__maybe_termination(HLDS26, Verbose, Stats, HLDS28), + mercury_compile__maybe_termination(HLDS25, Verbose, Stats, HLDS28), mercury_compile__maybe_dump_hlds(HLDS28, "28", "termination"), !, trans_opt__write_optfile(HLDS28). @@ -870,33 +871,36 @@ mercury_compile__frontend_pass_2_by_phases(HLDS4, HLDS20, FoundError) --> globals__io_lookup_bool_option(verbose, Verbose), globals__io_lookup_bool_option(statistics, Stats), - mercury_compile__modecheck(HLDS4, Verbose, Stats, HLDS5, + mercury_compile__maybe_polymorphism(HLDS4, Verbose, Stats, HLDS5), !, + mercury_compile__maybe_dump_hlds(HLDS5, "05", "polymorphism"), + + mercury_compile__modecheck(HLDS5, Verbose, Stats, HLDS6, FoundModeError, UnsafeToContinue), - mercury_compile__maybe_dump_hlds(HLDS5, "05", "modecheck"), + mercury_compile__maybe_dump_hlds(HLDS6, "06", "modecheck"), ( { UnsafeToContinue = yes } -> { FoundError = yes }, - { HLDS12 = HLDS5 } + { HLDS12 = HLDS6 } ; - mercury_compile__detect_switches(HLDS5, Verbose, Stats, HLDS6), + mercury_compile__detect_switches(HLDS6, Verbose, Stats, HLDS7), !, - mercury_compile__maybe_dump_hlds(HLDS6, "06", "switch_detect"), + mercury_compile__maybe_dump_hlds(HLDS7, "07", "switch_detect"), !, - mercury_compile__detect_cse(HLDS6, Verbose, Stats, HLDS7), !, - mercury_compile__maybe_dump_hlds(HLDS7, "07", "cse"), !, + mercury_compile__detect_cse(HLDS7, Verbose, Stats, HLDS8), !, + mercury_compile__maybe_dump_hlds(HLDS8, "08", "cse"), !, - mercury_compile__check_determinism(HLDS7, Verbose, Stats, HLDS8, + mercury_compile__check_determinism(HLDS8, Verbose, Stats, HLDS9, FoundDetError), !, - mercury_compile__maybe_dump_hlds(HLDS8, "08", "determinism"), + mercury_compile__maybe_dump_hlds(HLDS9, "09", "determinism"), !, - mercury_compile__check_unique_modes(HLDS8, Verbose, Stats, - HLDS9, FoundUniqError), !, - mercury_compile__maybe_dump_hlds(HLDS9, "09", "unique_modes"), + mercury_compile__check_unique_modes(HLDS9, Verbose, Stats, + HLDS10, FoundUniqError), !, + mercury_compile__maybe_dump_hlds(HLDS10, "10", "unique_modes"), !, - mercury_compile__check_stratification(HLDS9, Verbose, Stats, + mercury_compile__check_stratification(HLDS10, Verbose, Stats, HLDS11, FoundStratError), !, mercury_compile__maybe_dump_hlds(HLDS11, "11", "stratification"), !, @@ -953,16 +957,16 @@ mercury_compile__middle_pass(ModuleName, HLDS24, HLDS50) --> mercury_compile__tabling(HLDS24, Verbose, HLDS25), mercury_compile__maybe_dump_hlds(HLDS25, "25", "tabling"), !, - mercury_compile__maybe_polymorphism(HLDS25, Verbose, Stats, HLDS26), - mercury_compile__maybe_dump_hlds(HLDS26, "26", "polymorphism"), !, + mercury_compile__process_lambdas(HLDS25, Verbose, HLDS26), + mercury_compile__maybe_dump_hlds(HLDS26, "26", "lambda"), !, % % Uncomment the following code to check that unique mode analysis - % works after polymorphism has been run. Currently it does not + % works after simplification has been run. Currently it does not % because common.m does not preserve unique mode correctness % (this test fails on about five modules in the compiler and library). % It is important that unique mode analysis work most of the time - % after optimizations and polymorphism because deforestation reruns it. + % after optimizations because deforestation reruns it. % { HLDS27 = HLDS26 }, @@ -1529,8 +1533,8 @@ mercury_compile__maybe_generate_schemas(ModuleInfo, Verbose) --> %-----------------------------------------------------------------------------% -:- pred mercury_compile__tabling(module_info, bool, - module_info, io__state, io__state). +:- pred mercury_compile__tabling(module_info, bool, module_info, + io__state, io__state). :- mode mercury_compile__tabling(in, in, out, di, uo) is det. mercury_compile__tabling(HLDS0, Verbose, HLDS) --> @@ -1542,6 +1546,19 @@ mercury_compile__tabling(HLDS0, Verbose, HLDS) --> %-----------------------------------------------------------------------------% +:- pred mercury_compile__process_lambdas(module_info, bool, module_info, + io__state, io__state). +:- mode mercury_compile__process_lambdas(in, in, out, di, uo) is det. + +mercury_compile__process_lambdas(HLDS0, Verbose, HLDS) --> + maybe_write_string(Verbose, + "% Transforming lambda expressions..."), + maybe_flush_output(Verbose), + { lambda__process_module(HLDS0, HLDS) }, + maybe_write_string(Verbose, " done.\n"). + +%-----------------------------------------------------------------------------% + :- pred mercury_compile__maybe_polymorphism(module_info, bool, bool, module_info, io__state, io__state). :- mode mercury_compile__maybe_polymorphism(in, in, in, out, di, uo) is det. @@ -1556,7 +1573,11 @@ mercury_compile__maybe_polymorphism(HLDS0, Verbose, Stats, HLDS) --> maybe_write_string(Verbose, " done.\n"), maybe_report_stats(Stats) ; - { HLDS = HLDS0 } + % The --no-polymorphism option really doesn't make much + % sense anymore, because the polymorphism pass is necessary + % for the proper mode analysis of code using existential + % types. + { error("sorry, `--no-polymorphism' is no longer supported") } ). :- pred mercury_compile__maybe_type_ctor_infos(module_info, bool, bool, @@ -1693,7 +1714,7 @@ mercury_compile__maybe_deforestation(HLDS0, Verbose, Stats, HLDS) --> maybe_write_string(Verbose, "% Deforestation...\n"), maybe_flush_output(Verbose), deforestation(HLDS0, HLDS), - maybe_write_string(Verbose, " done.\n"), + maybe_write_string(Verbose, "% done.\n"), maybe_report_stats(Stats) ; { HLDS0 = HLDS } diff --git a/compiler/mercury_to_c.m b/compiler/mercury_to_c.m index c5fdf1c76..b0f2c8d01 100644 --- a/compiler/mercury_to_c.m +++ b/compiler/mercury_to_c.m @@ -1,5 +1,5 @@ %-----------------------------------------------------------------------------% -% Copyright (C) 1995-1998 The University of Melbourne. +% Copyright (C) 1995-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. %-----------------------------------------------------------------------------% @@ -177,8 +177,9 @@ c_gen_pred(Indent, ModuleInfo, PredId, PredInfo) --> ClassContext, Context), { pred_info_clauses_info(PredInfo, ClausesInfo) }, - { ClausesInfo = clauses_info(VarSet, _VarTypes, _, HeadVars, - Clauses) }, + { clauses_info_varset(ClausesInfo, VarSet) }, + { clauses_info_headvars(ClausesInfo, HeadVars) }, + { clauses_info_clauses(ClausesInfo, Clauses) }, globals__io_lookup_string_option(dump_hlds_options, Verbose), globals__io_set_option(dump_hlds_options, string("")), @@ -727,7 +728,7 @@ c_gen_unification(construct(_, _, _, _), _Indent, CGenInfo, CGenInfo) --> c_gen_unification(deconstruct(_, _, _, _, _), _Indent, CGenInfo, CGenInfo) --> { sorry(2) }, io__write_string(" == "). -c_gen_unification(complicated_unify(_, _), _Indent, CGenInfo, CGenInfo) --> +c_gen_unification(complicated_unify(_, _, _), _Indent, CGenInfo, CGenInfo) --> { sorry(3) }, io__write_string(" = "). diff --git a/compiler/mode_errors.m b/compiler/mode_errors.m index a76f5b330..67c8f2f9a 100644 --- a/compiler/mode_errors.m +++ b/compiler/mode_errors.m @@ -50,6 +50,9 @@ % the predicate variable in a higher-order predicate % or function call didn't have a higher-order % predicate or function inst of the appropriate arity + ; mode_error_poly_unify(prog_var, inst) + % A variable in a polymorphic unification with unknown + % type has inst other than `ground' or `any'. ; mode_error_var_is_live(prog_var) % call to a predicate which will clobber its argument, % but the argument is still live @@ -189,6 +192,8 @@ report_mode_error(mode_error_higher_order_pred_var(PredOrFunc, Var, Inst, Arity), ModeInfo) --> report_mode_error_higher_order_pred_var(ModeInfo, PredOrFunc, Var, Inst, Arity). +report_mode_error(mode_error_poly_unify(Var, Inst), ModeInfo) --> + report_mode_error_poly_unify(ModeInfo, Var, Inst). report_mode_error(mode_error_var_is_live(Var), ModeInfo) --> report_mode_error_var_is_live(ModeInfo, Var). report_mode_error(mode_error_var_has_inst(Var, InstA, InstB), ModeInfo) --> @@ -541,6 +546,37 @@ report_mode_error_higher_order_pred_var(ModeInfo, PredOrFunc, Var, VarInst, ), io__write_string(").\n"). +:- pred report_mode_error_poly_unify(mode_info, prog_var, inst, + io__state, io__state). +:- mode report_mode_error_poly_unify(mode_info_ui, in, in, di, uo) is det. + +report_mode_error_poly_unify(ModeInfo, Var, VarInst) --> + { mode_info_get_context(ModeInfo, Context) }, + { mode_info_get_varset(ModeInfo, VarSet) }, + { mode_info_get_instvarset(ModeInfo, InstVarSet) }, + mode_info_write_context(ModeInfo), + prog_out__write_context(Context), + io__write_string(" in polymorphically-typed unification:\n"), + prog_out__write_context(Context), + io__write_string(" mode error: variable `"), + mercury_output_var(Var, VarSet, no), + io__write_string("' has instantiatedness `"), + output_inst(VarInst, InstVarSet), + io__write_string("',\n"), + prog_out__write_context(Context), + io__write_string( + " expected instantiatedness was `ground' or `any'.\n"), + globals__io_lookup_bool_option(verbose_errors, VerboseErrors), + ( { VerboseErrors = yes } -> + io__write_string( +"\tWhen unifying two variables whose type will not be known until +\truntime, the variables must both be ground (or have inst `any'). +\tUnifications of polymorphically-typed variables with partially +\tinstantiated modes are not allowed.\n") + ; + [] + ). + :- pred report_mode_error_var_is_live(mode_info, prog_var, io__state, io__state). :- mode report_mode_error_var_is_live(mode_info_ui, in, di, uo) is det. @@ -888,7 +924,7 @@ write_mode_context(higher_order_call(PredOrFunc, ArgNum), Context, _ModuleInfo) write_mode_context(call(PredId, ArgNum), Context, ModuleInfo) --> prog_out__write_context(Context), io__write_string(" in "), - ( { ArgNum = 0 } -> + ( { ArgNum =< 0 } -> [] ; io__write_string("argument "), diff --git a/compiler/mode_info.m b/compiler/mode_info.m index 079f654d9..cb16ce5b6 100644 --- a/compiler/mode_info.m +++ b/compiler/mode_info.m @@ -28,7 +28,10 @@ :- type mode_context ---> call( pred_id, % pred name / arity - int % argument number + int % argument number (offset so that + % the real arguments start at number 1 + % whereas the type_info arguments + % have numbers <= 0). ) ; higher_order_call( pred_or_func, % is it call/N (higher-order pred call) @@ -573,6 +576,11 @@ mode_info_set_call_arg_context(ArgNum, ModeInfo0, ModeInfo) :- mode_info_set_mode_context( higher_order_call(PredOrFunc, ArgNum), ModeInfo0, ModeInfo) + ; ModeContext0 = unify(_UnifyContext, _Side) -> + % This only happens when checking that the typeinfo variables + % for polymorphic complicated unifications are ground. + % For that case, we don't care about the ArgNum. + ModeInfo = ModeInfo0 ; error("mode_info_set_call_arg_context") ). diff --git a/compiler/mode_util.m b/compiler/mode_util.m index 112ba10b5..d9a63b18c 100644 --- a/compiler/mode_util.m +++ b/compiler/mode_util.m @@ -1,5 +1,5 @@ %-----------------------------------------------------------------------------% -% Copyright (C) 1994-1998 The University of Melbourne. +% 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. %-----------------------------------------------------------------------------% @@ -157,11 +157,11 @@ %-----------------------------------------------------------------------------% -:- pred normalise_insts(list(inst), module_info, list(inst)). -:- mode normalise_insts(in, in, out) is det. +:- pred normalise_insts(list(inst), list(type), module_info, list(inst)). +:- mode normalise_insts(in, in, in, out) is det. -:- pred normalise_inst(inst, module_info, inst). -:- mode normalise_inst(in, in, out) is det. +:- pred normalise_inst(inst, (type), module_info, inst). +:- mode normalise_inst(in, in, in, out) is det. %-----------------------------------------------------------------------------% @@ -182,7 +182,7 @@ :- implementation. :- import_module require, int, map, set, std_util, assoc_list. -:- import_module prog_util, type_util. +:- import_module prog_util, prog_io, type_util. :- import_module inst_match, inst_util, term. %-----------------------------------------------------------------------------% @@ -1509,27 +1509,39 @@ strip_builtin_qualifiers_from_pred_inst(yes(Pred0), yes(Pred)) :- %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% -normalise_insts([], _, []). -normalise_insts([Inst0|Insts0], ModuleInfo, [Inst|Insts]) :- - normalise_inst(Inst0, ModuleInfo, Inst), - normalise_insts(Insts0, ModuleInfo, Insts). +normalise_insts([], [], _, []). +normalise_insts([Inst0|Insts0], [Type|Types], ModuleInfo, [Inst|Insts]) :- + normalise_inst(Inst0, Type, ModuleInfo, Inst), + normalise_insts(Insts0, Types, ModuleInfo, Insts). +normalise_insts([], [_|_], _, _) :- + error("normalise_insts: length mismatch"). +normalise_insts([_|_], [], _, _) :- + error("normalise_insts: length mismatch"). % This is a bit of a hack. % The aim is to avoid non-termination due to the creation % of ever-expanding insts. % XXX should also normalise partially instantiated insts. -normalise_inst(Inst0, ModuleInfo, NormalisedInst) :- +normalise_inst(Inst0, Type, ModuleInfo, NormalisedInst) :- inst_expand(ModuleInfo, Inst0, Inst), ( Inst = bound(_, _) -> ( inst_is_ground(ModuleInfo, Inst), - inst_is_unique(ModuleInfo, Inst) + inst_is_unique(ModuleInfo, Inst), + % don't infer unique modes for introduced type_infos + % arguments, because that leads to an increase + % in the number of inferred modes without any benefit + \+ is_introduced_type_info_type(Type) -> NormalisedInst = ground(unique, no) ; inst_is_ground(ModuleInfo, Inst), - inst_is_mostly_unique(ModuleInfo, Inst) + inst_is_mostly_unique(ModuleInfo, Inst), + % don't infer unique modes for introduced type_infos + % arguments, because that leads to an increase + % in the number of inferred modes without any benefit + \+ is_introduced_type_info_type(Type) -> NormalisedInst = ground(mostly_unique, no) ; diff --git a/compiler/modecheck_call.m b/compiler/modecheck_call.m index 04c2461a8..b2c568471 100644 --- a/compiler/modecheck_call.m +++ b/compiler/modecheck_call.m @@ -139,12 +139,14 @@ modecheck_higher_order_call(PredOrFunc, PredVar, Args0, Types, Modes, Det, Args, Det = Det0, Modes = Modes0, + ArgOffset = 1, + % % Check that `Args0' have livenesses which match the % expected livenesses. % get_arg_lives(Modes, ModuleInfo0, ExpectedArgLives), - modecheck_var_list_is_live(Args0, ExpectedArgLives, 1, + modecheck_var_list_is_live(Args0, ExpectedArgLives, ArgOffset, ModeInfo0, ModeInfo1), % @@ -153,11 +155,11 @@ modecheck_higher_order_call(PredOrFunc, PredVar, Args0, Types, Modes, Det, Args, % extra unifications for implied modes, if necessary). % mode_list_get_initial_insts(Modes, ModuleInfo0, InitialInsts), - modecheck_var_has_inst_list(Args0, InitialInsts, 0, + modecheck_var_has_inst_list(Args0, InitialInsts, ArgOffset, ModeInfo1, ModeInfo2), mode_list_get_final_insts(Modes, ModuleInfo0, FinalInsts), modecheck_set_var_inst_list(Args0, InitialInsts, FinalInsts, - Args, ExtraGoals, ModeInfo2, ModeInfo3), + ArgOffset, Args, ExtraGoals, ModeInfo2, ModeInfo3), ( determinism_components(Det, _, at_most_zero) -> instmap__init_unreachable(Instmap), mode_info_set_instmap(Instmap, ModeInfo3, ModeInfo) @@ -200,6 +202,7 @@ modecheck_call_pred(PredId, ProcId0, ArgVars0, DeterminismKnown, map__keys(Procs, ProcIds) ), + compute_arg_offset(PredInfo, ArgOffset), pred_info_get_markers(PredInfo, Markers), % In order to give better diagnostics, we handle the @@ -223,12 +226,13 @@ modecheck_call_pred(PredId, ProcId0, ArgVars0, DeterminismKnown, -> TheProcId = ProcId, map__lookup(Procs, ProcId, ProcInfo), + % % Check that `ArgsVars0' have livenesses which match the % expected livenesses. % proc_info_arglives(ProcInfo, ModuleInfo, ProcArgLives0), - modecheck_var_list_is_live(ArgVars0, ProcArgLives0, 0, + modecheck_var_list_is_live(ArgVars0, ProcArgLives0, ArgOffset, ModeInfo0, ModeInfo1), % @@ -239,10 +243,10 @@ modecheck_call_pred(PredId, ProcId0, ArgVars0, DeterminismKnown, proc_info_argmodes(ProcInfo, ProcArgModes), mode_list_get_initial_insts(ProcArgModes, ModuleInfo, InitialInsts), - modecheck_var_has_inst_list(ArgVars0, InitialInsts, 0, + modecheck_var_has_inst_list(ArgVars0, InitialInsts, ArgOffset, ModeInfo1, ModeInfo2), - modecheck_end_of_call(ProcInfo, ArgVars0, ArgVars, + modecheck_end_of_call(ProcInfo, ArgVars0, ArgOffset, ArgVars, ExtraGoals, ModeInfo2, ModeInfo) ; % set the current error list to empty (and @@ -269,8 +273,8 @@ modecheck_call_pred(PredId, ProcId0, ArgVars0, DeterminismKnown, choose_best_match(MatchingProcIds, PredId, Procs, ArgVars0, TheProcId, ModeInfo2), map__lookup(Procs, TheProcId, ProcInfo), - modecheck_end_of_call(ProcInfo, ArgVars0, ArgVars, - ExtraGoals, ModeInfo2, ModeInfo3) + modecheck_end_of_call(ProcInfo, ArgVars0, ArgOffset, + ArgVars, ExtraGoals, ModeInfo2, ModeInfo3) ), % restore the error list, appending any new error(s) @@ -370,19 +374,19 @@ modecheck_find_matching_modes([ProcId | ProcIds], PredId, Procs, ArgVars0, MatchingProcIds1, MatchingProcIds, WaitingVars1, WaitingVars, ModeInfo3, ModeInfo). -:- pred modecheck_end_of_call(proc_info, list(prog_var), list(prog_var), - extra_goals, mode_info, mode_info). -:- mode modecheck_end_of_call(in, in, out, out, +:- pred modecheck_end_of_call(proc_info, list(prog_var), int, + list(prog_var), extra_goals, mode_info, mode_info). +:- mode modecheck_end_of_call(in, in, in, out, out, mode_info_di, mode_info_uo) is det. -modecheck_end_of_call(ProcInfo, ArgVars0, ArgVars, ExtraGoals, - ModeInfo0, ModeInfo) :- +modecheck_end_of_call(ProcInfo, ArgVars0, ArgOffset, + ArgVars, ExtraGoals, ModeInfo0, ModeInfo) :- proc_info_argmodes(ProcInfo, ProcArgModes), mode_info_get_module_info(ModeInfo0, ModuleInfo), mode_list_get_initial_insts(ProcArgModes, ModuleInfo, InitialInsts), mode_list_get_final_insts(ProcArgModes, ModuleInfo, FinalInsts), modecheck_set_var_inst_list(ArgVars0, InitialInsts, FinalInsts, - ArgVars, ExtraGoals, ModeInfo0, ModeInfo1), + ArgOffset, ArgVars, ExtraGoals, ModeInfo0, ModeInfo1), proc_info_never_succeeds(ProcInfo, NeverSucceeds), ( NeverSucceeds = yes -> instmap__init_unreachable(Instmap), @@ -437,8 +441,10 @@ get_var_insts_and_lives([Var | Vars], ModeInfo, [Inst | Insts], [IsLive | IsLives]) :- mode_info_get_module_info(ModeInfo, ModuleInfo), mode_info_get_instmap(ModeInfo, InstMap), + mode_info_get_var_types(ModeInfo, VarTypes), instmap__lookup_var(InstMap, Var, Inst0), - normalise_inst(Inst0, ModuleInfo, Inst), + map__lookup(VarTypes, Var, Type), + normalise_inst(Inst0, Type, ModuleInfo, Inst), mode_info_var_is_live(ModeInfo, Var, IsLive0), diff --git a/compiler/modecheck_unify.m b/compiler/modecheck_unify.m index 0d66f6fb5..84f8297be 100644 --- a/compiler/modecheck_unify.m +++ b/compiler/modecheck_unify.m @@ -20,8 +20,7 @@ :- module modecheck_unify. :- interface. -:- import_module hlds_goal, hlds_data, prog_data, mode_info. -:- import_module map. +:- import_module hlds_goal, prog_data, mode_info. % Modecheck a unification :- pred modecheck_unification(prog_var, unify_rhs, unification, unify_context, @@ -29,18 +28,11 @@ :- mode modecheck_unification(in, in, in, in, in, out, mode_info_di, mode_info_uo) is det. - % Work out what kind of unification a var-var unification is. -:- pred categorize_unify_var_var(mode, mode, is_live, is_live, prog_var, - prog_var, determinism, unify_context, map(prog_var, type), - mode_info, hlds_goal_expr, mode_info). -:- mode categorize_unify_var_var(in, in, in, in, in, in, in, in, in, - mode_info_di, out, mode_info_uo) is det. - % Create a unification between the two given variables. % The goal's mode and determinism information is not filled in. -:- pred modecheck_unify__create_var_var_unification(prog_var, prog_var, +:- pred modecheck_unify__create_var_var_unification(prog_var, prog_var, type, mode_info, hlds_goal). -:- mode modecheck_unify__create_var_var_unification(in, in, +:- mode modecheck_unify__create_var_var_unification(in, in, in, mode_info_ui, out) is det. %-----------------------------------------------------------------------------% @@ -49,18 +41,19 @@ :- implementation. :- import_module llds, prog_util, type_util, module_qual, instmap. -:- import_module hlds_module, hlds_goal, hlds_pred, hlds_out. +:- import_module hlds_module, hlds_goal, hlds_pred, hlds_data, hlds_out. :- import_module mode_debug, mode_util, mode_info, modes, mode_errors. :- import_module inst_match, inst_util, unify_proc, code_util, unique_modes. :- import_module typecheck, modecheck_call, (inst), quantification, make_hlds. +:- import_module polymorphism. -:- import_module bool, list, std_util, int, set, require. +:- import_module bool, list, map, std_util, int, set, require. :- import_module string, assoc_list. :- import_module term, varset. %-----------------------------------------------------------------------------% -modecheck_unification(X, var(Y), _Unification0, UnifyContext, _GoalInfo, +modecheck_unification(X, var(Y), Unification0, UnifyContext, _GoalInfo, Unify, ModeInfo0, ModeInfo) :- mode_info_get_module_info(ModeInfo0, ModuleInfo0), mode_info_get_instmap(ModeInfo0, InstMap0), @@ -86,7 +79,8 @@ modecheck_unification(X, var(Y), _Unification0, UnifyContext, _GoalInfo, ModeOfY = (InstOfY -> Inst), mode_info_get_var_types(ModeInfo3, VarTypes), categorize_unify_var_var(ModeOfX, ModeOfY, LiveX, LiveY, X, Y, - Det, UnifyContext, VarTypes, ModeInfo3, Unify, ModeInfo) + Det, UnifyContext, VarTypes, Unification0, ModeInfo3, + Unify, ModeInfo) ; set__list_to_set([X, Y], WaitingVars), mode_info_error(WaitingVars, mode_error_unify_var_var(X, Y, @@ -112,96 +106,6 @@ modecheck_unification(X0, functor(ConsId0, ArgVars0), Unification0, mode_info_get_module_info(ModeInfo0, ModuleInfo0), mode_info_get_var_types(ModeInfo0, VarTypes0), map__lookup(VarTypes0, X0, TypeOfX), - module_info_get_predicate_table(ModuleInfo0, PredTable), - list__length(ArgVars0, Arity), - mode_info_get_predid(ModeInfo0, ThisPredId), - mode_info_get_how_to_check(ModeInfo0, HowToCheckGoal), - ( - % - % is the function symbol apply/N or ''/N, - % representing a higher-order function call? - % - % (As an optimization, if HowToCheck = check_unique_modes, - % then don't bother checking, since they will have already - % been expanded.) - % - HowToCheckGoal \= check_unique_modes, - ConsId0 = cons(unqualified(ApplyName), _), - ( ApplyName = "apply" ; ApplyName = "" ), - Arity >= 1, - ArgVars0 = [FuncVar | FuncArgVars] - -> - % - % Convert the higher-order function call (apply/N) - % into a higher-order predicate call - % (i.e., replace `X = apply(F, A, B, C)' - % with `call(F, A, B, C, X)') - % and then mode-check it. - % - modecheck_higher_order_func_call(FuncVar, FuncArgVars, X0, - GoalInfo0, Goal, ModeInfo0, ModeInfo) - ; - % - % is the function symbol a user-defined function, rather - % than a functor which represents a data constructor? - % - - % As an optimization, if HowToCheck = check_unique_modes, - % then don't bother checking, since they will have already - % been expanded. - HowToCheckGoal \= check_unique_modes, - - % Find the set of candidate predicates which have the - % specified name and arity (and module, if module-qualified) - ConsId0 = cons(PredName, _), - module_info_pred_info(ModuleInfo0, ThisPredId, PredInfo), - - % - % We don't do this for compiler-generated predicates; - % they are assumed to have been generated with all - % functions already expanded. - % If we did this check for compiler-generated - % predicates, it would cause the wrong behaviour - % in the case where there is a user-defined function - % whose type is exactly the same as the type of - % a constructor. (Normally that would cause - % a type ambiguity error, but compiler-generated - % predicates are not type-checked.) - % - - \+ code_util__compiler_generated(PredInfo), - - predicate_table_search_func_sym_arity(PredTable, - PredName, Arity, PredIds), - - % Check if any of the candidate functions have - % argument/return types which subsume the actual - % argument/return types of this function call - - pred_info_typevarset(PredInfo, TVarSet), - map__apply_to_list(ArgVars0, VarTypes0, ArgTypes0), - list__append(ArgTypes0, [TypeOfX], ArgTypes), - typecheck__find_matching_pred_id(PredIds, ModuleInfo0, - TVarSet, ArgTypes, PredId, QualifiedFuncName) - -> - % - % Convert function calls into predicate calls: - % replace `X = f(A, B, C)' - % with `f(A, B, C, X)' - % - invalid_proc_id(ProcId), - list__append(ArgVars0, [X0], ArgVars), - FuncCallUnifyContext = call_unify_context(X0, - functor(ConsId0, ArgVars0), UnifyContext), - FuncCall = call(PredId, ProcId, ArgVars, not_builtin, - yes(FuncCallUnifyContext), QualifiedFuncName), - % - % now modecheck it - % - modecheck_goal_expr(FuncCall, GoalInfo0, Goal, ModeInfo0, ModeInfo) - - ; - % % We replace any unifications with higher-order pred constants % by lambda expressions. For example, we replace @@ -212,18 +116,13 @@ modecheck_unification(X0, functor(ConsId0, ArgVars0), Unification0, % % X = lambda [A1::in, A2::out] (list__append(Y, A1, A2)) % - % We do this because it makes two things easier. - % Firstly, we need to check that the lambda-goal doesn't - % bind any non-local variables (e.g. `Y' in above example). - % This would require a bit of moderately tricky special-case code - % if we didn't expand them. - % Secondly, the polymorphism pass (polymorphism.m) is a lot easier - % if we don't have to handle higher-order pred consts. - % If it turns out that the predicate was non-polymorphic, - % lambda.m will (I hope) turn the lambda expression - % back into a higher-order pred constant again. + % Normally this is done by polymorphism__process_unify_functor, + % but if we're re-modechecking goals after lambda.m has been run + % (e.g. for deforestation), then we may need to do it again here. + % Note that any changes to this code here will probably need to be + % duplicated there too. % - + ( % check if variable has a higher-order type type_is_higher_order(TypeOfX, PredOrFunc, PredArgTypes), ConsId0 = cons(PName, _), @@ -234,89 +133,23 @@ modecheck_unification(X0, functor(ConsId0, ArgVars0), Unification0, Unification0 \= deconstruct(_, code_addr_const(_, _), _, _, _) -> % - % Create the new lambda-quantified variables + % convert the pred term to a lambda expression % mode_info_get_varset(ModeInfo0, VarSet0), - make_fresh_vars(PredArgTypes, VarSet0, VarTypes0, - LambdaVars, VarSet, VarTypes), - list__append(ArgVars0, LambdaVars, Args), - mode_info_set_varset(VarSet, ModeInfo0, ModeInfo1), - mode_info_set_var_types(VarTypes, ModeInfo1, ModeInfo2), - - % - % Build up the hlds_goal_expr for the call that will form - % the lambda goal - % - + mode_info_get_context(ModeInfo0, Context), + mode_info_get_predid(ModeInfo0, ThisPredId), module_info_pred_info(ModuleInfo0, ThisPredId, ThisPredInfo), pred_info_typevarset(ThisPredInfo, TVarSet), - map__apply_to_list(Args, VarTypes, ArgTypes), - ( - % If we are redoing mode analysis, use the - % pred_id and proc_id found before, to avoid aborting - % in get_pred_id_and_proc_id if there are multiple - % matching procedures. - Unification0 = construct(_, - pred_const(PredId0, ProcId0), _, _) - -> - PredId = PredId0, - ProcId = ProcId0 - ; - get_pred_id_and_proc_id(PName, PredOrFunc, TVarSet, - ArgTypes, ModuleInfo0, PredId, ProcId) - ), - module_info_pred_proc_info(ModuleInfo0, PredId, ProcId, - PredInfo, ProcInfo), - - % module-qualify the pred name (is this necessary?) - pred_info_module(PredInfo, PredModule), - unqualify_name(PName, UnqualPName), - QualifiedPName = qualified(PredModule, UnqualPName), - - CallUnifyContext = call_unify_context(X0, - functor(ConsId0, ArgVars0), UnifyContext), - LambdaGoalExpr = call(PredId, ProcId, Args, not_builtin, - yes(CallUnifyContext), QualifiedPName), - + convert_pred_to_lambda_goal(PredOrFunc, X0, ConsId0, PName, + ArgVars0, PredArgTypes, TVarSet, + Unification0, UnifyContext, GoalInfo0, Context, + ModuleInfo0, VarSet0, VarTypes0, + Functor0, VarSet, VarTypes), + mode_info_set_varset(VarSet, ModeInfo0, ModeInfo1), + mode_info_set_var_types(VarTypes, ModeInfo1, ModeInfo2), % - % construct a goal_info for the lambda goal, making sure - % to set up the nonlocals field in the goal_info correctly + % modecheck this unification in its new form % - goal_info_get_nonlocals(GoalInfo0, NonLocals), - set__insert_list(NonLocals, LambdaVars, OutsideVars), - set__list_to_set(Args, InsideVars), - set__intersect(OutsideVars, InsideVars, LambdaNonLocals), - goal_info_init(LambdaGoalInfo0), - mode_info_get_context(ModeInfo2, Context), - goal_info_set_context(LambdaGoalInfo0, Context, - LambdaGoalInfo1), - goal_info_set_nonlocals(LambdaGoalInfo1, LambdaNonLocals, - LambdaGoalInfo), - LambdaGoal = LambdaGoalExpr - LambdaGoalInfo, - - % - % work out the modes of the introduced lambda variables - % and the determinism of the lambda goal - % - proc_info_argmodes(ProcInfo, ArgModes), - ( list__drop(Arity, ArgModes, LambdaModes0) -> - LambdaModes = LambdaModes0 - ; - error("modecheck_unification: list__drop failed") - ), - proc_info_declared_determinism(ProcInfo, MaybeDet), - ( MaybeDet = yes(Det) -> - LambdaDet = Det - ; - error("Sorry, not implemented: determinism inference for higher-order predicate terms") - ), - - % - % construct the lambda expression, and then go ahead - % and modecheck this unification in its new form - % - Functor0 = lambda_goal(PredOrFunc, ArgVars0, LambdaVars, - LambdaModes, LambdaDet, LambdaGoal), modecheck_unification( X0, Functor0, Unification0, UnifyContext, GoalInfo0, Goal, ModeInfo2, ModeInfo) ; @@ -574,14 +407,13 @@ modecheck_unify_functor(X, TypeOfX, ConsId0, ArgVars0, Unification0, % fully module qualify all cons_ids % (except for builtins such as ints and characters). % - list__length(ArgVars0, Arity), ( - ConsId0 = cons(Name, _), + ConsId0 = cons(Name, OrigArity), type_to_type_id(TypeOfX, TypeId, _), TypeId = qualified(TypeModule, _) - _ -> unqualify_name(Name, UnqualName), - ConsId = cons(qualified(TypeModule, UnqualName), Arity) + ConsId = cons(qualified(TypeModule, UnqualName), OrigArity) ; ConsId = ConsId0 ), @@ -645,6 +477,7 @@ modecheck_unify_functor(X, TypeOfX, ConsId0, ArgVars0, Unification0, ), ( inst_expand(ModuleInfo1, InstOfX, InstOfX1), + list__length(ArgVars0, Arity), get_arg_insts(InstOfX1, ConsId, Arity, InstOfXArgs), get_mode_of_args(Inst, InstOfXArgs, ModeOfXArgs0) -> @@ -810,7 +643,7 @@ split_complicated_subunifies_2([Var0 | Vars0], [UniMode0 | UniModes0], mode_info_set_var_types(VarTypes, ModeInfo1, ModeInfo2), modecheck_unify__create_var_var_unification(Var0, Var, - ModeInfo2, ExtraGoal), + VarType, ModeInfo2, ExtraGoal), % insert the new unification at % the start of the extra goals @@ -827,32 +660,68 @@ split_complicated_subunifies_2([Var0 | Vars0], [UniMode0 | UniModes0], Vars = [Var0 | Vars1] ). -modecheck_unify__create_var_var_unification(Var0, Var, ModeInfo, - ExtraGoal - GoalInfo) :- +modecheck_unify__create_var_var_unification(Var0, Var, Type, ModeInfo, + Goal - GoalInfo) :- mode_info_get_context(ModeInfo, Context), mode_info_get_mode_context(ModeInfo, ModeContext), mode_context_to_unify_context(ModeContext, ModeInfo, UnifyContext), UnifyContext = unify_context(MainContext, SubContexts), create_atomic_unification(Var0, var(Var), Context, - MainContext, SubContexts, ExtraGoal - GoalInfo0), - - % compute the goal_info nonlocal vars - % for the newly created goal + MainContext, SubContexts, Goal0 - GoalInfo0), + + % + % compute the goal_info nonlocal vars for the newly created goal + % (excluding the type_info vars -- they are added below). % N.B. This may overestimate the set of non-locals, % but that shouldn't cause any problems. + % set__list_to_set([Var0, Var], NonLocals), goal_info_set_nonlocals(GoalInfo0, NonLocals, GoalInfo1), - goal_info_set_context(GoalInfo1, Context, GoalInfo). + goal_info_set_context(GoalInfo1, Context, GoalInfo2), + % + % Look up the map(tvar, type_info_locn) in the proc_info, + % since it is needed by polymorphism__unification_typeinfos + % + mode_info_get_module_info(ModeInfo, ModuleInfo), + mode_info_get_predid(ModeInfo, PredId), + mode_info_get_procid(ModeInfo, ProcId), + module_info_pred_proc_info(ModuleInfo, PredId, ProcId, + _PredInfo, ProcInfo), + proc_info_typeinfo_varmap(ProcInfo, TypeInfoVarMap), + + % + % Call polymorphism__unification_typeinfos to add the appropriate + % type-info and type-class-info variables to the nonlocals + % and to the unification. + % + ( + Goal0 = unify(X, Y, Mode, Unification0, FinalUnifyContext) + -> + polymorphism__unification_typeinfos(Type, TypeInfoVarMap, + Unification0, GoalInfo2, Unification, GoalInfo), + Goal = unify(X, Y, Mode, Unification, FinalUnifyContext) + ; + error("modecheck_unify__create_var_var_unification") + ). + %-----------------------------------------------------------------------------% + % Work out what kind of unification a var-var unification is. +:- pred categorize_unify_var_var(mode, mode, is_live, is_live, prog_var, + prog_var, determinism, unify_context, map(prog_var, type), + unification, mode_info, hlds_goal_expr, mode_info). +:- mode categorize_unify_var_var(in, in, in, in, in, in, in, in, in, in, + mode_info_di, out, mode_info_uo) is det. + % categorize_unify_var_var works out which category a unification % between a variable and another variable expression is - whether it is % an assignment, a simple test or a complicated unify. categorize_unify_var_var(ModeOfX, ModeOfY, LiveX, LiveY, X, Y, Det, - UnifyContext, VarTypes, ModeInfo0, Unify, ModeInfo) :- + UnifyContext, VarTypes, Unification0, ModeInfo0, + Unify, ModeInfo) :- mode_info_get_module_info(ModeInfo0, ModuleInfo0), ( mode_is_output(ModuleInfo0, ModeOfX) @@ -879,6 +748,21 @@ categorize_unify_var_var(ModeOfX, ModeOfY, LiveX, LiveY, X, Y, Det, error("categorize_unify_var_var: free-free unify!") ), ModeInfo = ModeInfo0 + ; + % + % Check for unreachable unifications + % + ( mode_get_insts(ModuleInfo0, ModeOfX, not_reached, _) + ; mode_get_insts(ModuleInfo0, ModeOfY, not_reached, _) + ) + -> + % + % For these, we can generate any old junk here -- + % we just need to avoid calling modecheck_complicated_unify, + % since that might abort. + % + Unification = simple_test(X, Y), + ModeInfo = ModeInfo0 ; map__lookup(VarTypes, X, Type), ( @@ -887,49 +771,10 @@ categorize_unify_var_var(ModeOfX, ModeOfY, LiveX, LiveY, X, Y, Det, Unification = simple_test(X, Y), ModeInfo = ModeInfo0 ; - mode_get_insts(ModuleInfo0, ModeOfX, IX, FX), - mode_get_insts(ModuleInfo0, ModeOfY, IY, FY), - determinism_components(Det, CanFail, _), - UniMode = ((IX - IY) -> (FX - FY)), - Unification = complicated_unify(UniMode, CanFail), - mode_info_get_instmap(ModeInfo0, InstMap0), - ( - type_is_higher_order(Type, PredOrFunc, _) - -> - % We do not want to report this as an error - % if it occurs in a compiler-generated - % predicate - instead, we delay the error - % until runtime so that it only occurs if - % the compiler-generated predicate gets called. - % not_reached is considered bound, so the - % error message would be spurious if the - % instmap is unreachable. - mode_info_get_predid(ModeInfo0, PredId), - module_info_pred_info(ModuleInfo0, PredId, - PredInfo), - ( - ( code_util__compiler_generated(PredInfo) - ; instmap__is_unreachable(InstMap0) - ) - -> - ModeInfo = ModeInfo0 - ; - set__init(WaitingVars), - mode_info_error(WaitingVars, - mode_error_unify_pred(X, error_at_var(Y), Type, PredOrFunc), - ModeInfo0, ModeInfo) - ) - ; - type_to_type_id(Type, TypeId, _) - -> - mode_info_get_context(ModeInfo0, Context), - unify_proc__request_unify(TypeId - UniMode, - Det, Context, ModuleInfo0, ModuleInfo), - mode_info_set_module_info(ModeInfo0, ModuleInfo, - ModeInfo) - ; - ModeInfo = ModeInfo0 - ) + modecheck_complicated_unify(X, Y, + Type, ModeOfX, ModeOfY, Det, UnifyContext, + Unification0, ModeInfo0, + Unification, ModeInfo) ) ), % @@ -969,6 +814,132 @@ categorize_unify_var_var(ModeOfX, ModeOfY, LiveX, LiveY, X, Y, Det, UnifyContext) ). +% +% modecheck_complicated_unify does some extra checks that are needed +% for mode-checking complicated unifications. +% + +:- pred modecheck_complicated_unify(prog_var, prog_var, + type, mode, mode, determinism, unify_context, + unification, mode_info, unification, mode_info). +:- mode modecheck_complicated_unify(in, in, in, in, in, in, in, + in, mode_info_di, out, mode_info_uo) is det. + +modecheck_complicated_unify(X, Y, Type, ModeOfX, ModeOfY, Det, UnifyContext, + Unification0, ModeInfo0, Unification, ModeInfo) :- + % + % Build up the unification + % + mode_info_get_module_info(ModeInfo0, ModuleInfo0), + mode_get_insts(ModuleInfo0, ModeOfX, InitialInstX, FinalInstX), + mode_get_insts(ModuleInfo0, ModeOfY, InitialInstY, FinalInstY), + UniMode = ((InitialInstX - InitialInstY) -> (FinalInstX - FinalInstY)), + determinism_components(Det, CanFail, _), + ( Unification0 = complicated_unify(_, _, UnifyTypeInfoVars0) -> + UnifyTypeInfoVars = UnifyTypeInfoVars0 + ; + error("modecheck_complicated_unify") + ), + Unification = complicated_unify(UniMode, CanFail, UnifyTypeInfoVars), + + % + % check that all the type_info or type_class_info variables used + % by the polymorphic unification are ground. + % + ( UnifyTypeInfoVars = [] -> + % optimize common case + ModeInfo2 = ModeInfo0 + ; + list__length(UnifyTypeInfoVars, NumTypeInfoVars), + list__duplicate(NumTypeInfoVars, ground(shared, no), + ExpectedInsts), + mode_info_set_call_context(unify(UnifyContext), + ModeInfo0, ModeInfo1), + InitialArgNum = 0, + modecheck_var_has_inst_list(UnifyTypeInfoVars, ExpectedInsts, + InitialArgNum, ModeInfo1, ModeInfo2) + ), + + mode_info_get_module_info(ModeInfo2, ModuleInfo2), + + ( + mode_info_get_errors(ModeInfo2, Errors), + Errors \= [] + -> + ModeInfo = ModeInfo2 + ; + % + % Check that we're not trying to do a polymorphic unification + % in a mode other than (in, in). + % [Actually we also allow `any' insts, since the (in, in) + % mode of unification for types which have `any' insts must + % also be able to handle (in(any), in(any)) unifications.] + % + Type = term__variable(_), + \+ inst_is_ground_or_any(ModuleInfo2, InitialInstX) + -> + set__singleton_set(WaitingVars, X), + mode_info_error(WaitingVars, + mode_error_poly_unify(X, InitialInstX), + ModeInfo2, ModeInfo) + ; + Type = term__variable(_), + \+ inst_is_ground_or_any(ModuleInfo2, InitialInstY) + -> + set__singleton_set(WaitingVars, Y), + mode_info_error(WaitingVars, + mode_error_poly_unify(Y, InitialInstY), + ModeInfo2, ModeInfo) + ; + + % + % check that we're not trying to do a higher-order unification + % + type_is_higher_order(Type, PredOrFunc, _) + -> + % We do not want to report this as an error + % if it occurs in a compiler-generated + % predicate - instead, we delay the error + % until runtime so that it only occurs if + % the compiler-generated predicate gets called. + % not_reached is considered bound, so the + % error message would be spurious if the + % instmap is unreachable. + mode_info_get_predid(ModeInfo2, PredId), + module_info_pred_info(ModuleInfo2, PredId, + PredInfo), + mode_info_get_instmap(ModeInfo2, InstMap0), + ( + ( code_util__compiler_generated(PredInfo) + ; instmap__is_unreachable(InstMap0) + ) + -> + ModeInfo = ModeInfo2 + ; + set__init(WaitingVars), + mode_info_error(WaitingVars, + mode_error_unify_pred(X, error_at_var(Y), + Type, PredOrFunc), + ModeInfo2, ModeInfo) + ) + ; + % + % Ensure that we will generate code for the unification + % procedure that will be used to implement this complicated + % unification. + % + type_to_type_id(Type, TypeId, _) + -> + mode_info_get_context(ModeInfo2, Context), + unify_proc__request_unify(TypeId - UniMode, + Det, Context, ModuleInfo2, ModuleInfo), + mode_info_set_module_info(ModeInfo2, ModuleInfo, + ModeInfo) + ; + ModeInfo = ModeInfo2 + ). + + % categorize_unify_var_lambda works out which category a unification % between a variable and a lambda expression is - whether it is a construction % unification or a deconstruction. It also works out whether it will @@ -990,7 +961,7 @@ categorize_unify_var_lambda(ModeOfX, ArgModes0, X, ArgVars, ; Unification0 = deconstruct(_, ConsId1, _, _, _) -> ConsId = ConsId1 ; - % the real cons_id will be computed by polymorphism.m; + % the real cons_id will be computed by lambda.m; % we just put in a dummy one for now ConsId = cons(unqualified("__LambdaGoal__"), Arity) ), @@ -1218,18 +1189,5 @@ mode_set_args([Inst | Insts], FinalInst, [Mode | Modes]) :- Mode = (Inst -> FinalInst), mode_set_args(Insts, FinalInst, Modes). -%-----------------------------------------------------------------------------% - -:- pred make_fresh_vars(list(type), prog_varset, map(prog_var, type), - list(prog_var), prog_varset, map(prog_var, type)). -:- mode make_fresh_vars(in, in, in, out, out, out) is det. - -make_fresh_vars([], VarSet, VarTypes, [], VarSet, VarTypes). -make_fresh_vars([Type|Types], VarSet0, VarTypes0, - [Var|Vars], VarSet, VarTypes) :- - varset__new_var(VarSet0, Var, VarSet1), - map__det_insert(VarTypes0, Var, Type, VarTypes1), - make_fresh_vars(Types, VarSet1, VarTypes1, Vars, VarSet, VarTypes). - %-----------------------------------------------------------------------------% %-----------------------------------------------------------------------------% diff --git a/compiler/modes.m b/compiler/modes.m index e14a58ba0..c0336f582 100644 --- a/compiler/modes.m +++ b/compiler/modes.m @@ -202,6 +202,16 @@ a variable live if its value will be used later on in the computation. :- pred get_live_vars(list(prog_var), list(is_live), list(prog_var)). :- mode get_live_vars(in, in, out) is det. + % + % calculate the argument number offset that needs to be passed to + % modecheck_var_list_is_live, modecheck_var_has_inst_list, and + % modecheck_set_var_inst_list. This offset number is calculated + % so that real arguments get positive argument numbers and + % type_info arguments get argument numbers less than or equal to 0. + % +:- pred compute_arg_offset(pred_info, int). +:- mode compute_arg_offset(in, out) is det. + % Given a list of variables and a list of expected liveness, ensure % that the inst of each variable satisfies the corresponding expected % liveness. @@ -224,8 +234,8 @@ a variable live if its value will be used later on in the computation. :- mode modecheck_set_var_inst(in, in, mode_info_di, mode_info_uo) is det. :- pred modecheck_set_var_inst_list(list(prog_var), list(inst), list(inst), - list(prog_var), extra_goals, mode_info, mode_info). -:- mode modecheck_set_var_inst_list(in, in, in, out, out, + int, list(prog_var), extra_goals, mode_info, mode_info). +:- mode modecheck_set_var_inst_list(in, in, in, in, out, out, mode_info_di, mode_info_uo) is det. % check that the final insts of the head vars of a lambda @@ -392,6 +402,7 @@ modecheck_to_fixpoint(PredIds, MaxIterations, WhatToCheck, MayChangeCalledProc, ; [] ), + % % Mode analysis may have modified the procedure % bodies, since it does some optimizations such @@ -402,6 +413,7 @@ modecheck_to_fixpoint(PredIds, MaxIterations, WhatToCheck, MayChangeCalledProc, % they may therefore produce incorrect results. % Thus we need to restore the old procedure bodies. % + ( { WhatToCheck = check_modes } -> % restore the proc_info goals from the % clauses in the pred_info @@ -413,6 +425,7 @@ modecheck_to_fixpoint(PredIds, MaxIterations, WhatToCheck, MayChangeCalledProc, { copy_pred_bodies(OldPredTable, PredIds, ModuleInfo3, ModuleInfo4) } ), + { MaxIterations1 is MaxIterations - 1 }, modecheck_to_fixpoint(PredIds, MaxIterations1, WhatToCheck, MayChangeCalledProc, @@ -453,14 +466,25 @@ copy_pred_bodies(OldPredTable, PredIds, ModuleInfo0, ModuleInfo) :- :- mode copy_pred_body(in, in, in, out) is det. copy_pred_body(OldPredTable, PredId, PredTable0, PredTable) :- map__lookup(PredTable0, PredId, PredInfo0), - pred_info_procedures(PredInfo0, ProcTable0), - map__lookup(OldPredTable, PredId, OldPredInfo), - pred_info_procedures(OldPredInfo, OldProcTable), - map__keys(OldProcTable, OldProcIds), - list__foldl(copy_proc_body(OldProcTable), OldProcIds, - ProcTable0, ProcTable), - pred_info_set_procedures(PredInfo0, ProcTable, PredInfo), - map__set(PredTable0, PredId, PredInfo, PredTable). + ( + % don't copy type class methods, because their + % proc_infos are generated already mode-correct, + % and because copying from the clauses_info doesn't + % work for them. + pred_info_get_markers(PredInfo0, Markers), + check_marker(Markers, class_method) + -> + PredTable = PredTable0 + ; + pred_info_procedures(PredInfo0, ProcTable0), + map__lookup(OldPredTable, PredId, OldPredInfo), + pred_info_procedures(OldPredInfo, OldProcTable), + map__keys(OldProcTable, OldProcIds), + list__foldl(copy_proc_body(OldProcTable), OldProcIds, + ProcTable0, ProcTable), + pred_info_set_procedures(PredInfo0, ProcTable, PredInfo), + map__set(PredTable0, PredId, PredInfo, PredTable) + ). % copy_proc_body(OldProcTable, ProcId, ProcTable0, ProcTable): % copy the body of the specified ProcId from OldProcTable @@ -487,11 +511,24 @@ modecheck_pred_modes_2([PredId | PredIds], WhatToCheck, MayChangeCalledProc, NumErrors0, NumErrors) --> { module_info_preds(ModuleInfo0, Preds0) }, { map__lookup(Preds0, PredId, PredInfo0) }, - ( { pred_info_is_imported(PredInfo0) } -> - { ModuleInfo3 = ModuleInfo0 }, - { Changed1 = Changed0 }, - { NumErrors1 = NumErrors0 } - ; { pred_info_is_pseudo_imported(PredInfo0) } -> + ( + ( + % + % don't modecheck imported predicates + % + ( { pred_info_is_imported(PredInfo0) } + ; { pred_info_is_pseudo_imported(PredInfo0) } + ) + ; + % + % don't modecheck class methods, because they + % are generated already mode-correct and with + % correct instmap deltas. + % + { pred_info_get_markers(PredInfo0, PredMarkers) }, + { check_marker(PredMarkers, class_method) } + ) + -> { ModuleInfo3 = ModuleInfo0 }, { Changed1 = Changed0 }, { NumErrors1 = NumErrors0 } @@ -717,7 +754,7 @@ modecheck_proc_3(ProcId, PredId, WhatToCheck, MayChangeCalledProc, % we use the context of the mode declaration. module_info_pred_info(ModuleInfo0, PredId, PredInfo), pred_info_clauses_info(PredInfo, ClausesInfo), - ClausesInfo = clauses_info(_, _, _, _, ClauseList), + clauses_info_clauses(ClausesInfo, ClauseList), ( ClauseList = [FirstClause | _] -> FirstClause = clause(_, _, Context) ; @@ -800,10 +837,13 @@ modecheck_final_insts_2(HeadVars, FinalInsts0, ModeInfo0, InferModes, FinalInsts, ModeInfo) :- mode_info_get_module_info(ModeInfo0, ModuleInfo), mode_info_get_instmap(ModeInfo0, InstMap), + mode_info_get_var_types(ModeInfo0, VarTypes), instmap__lookup_vars(HeadVars, InstMap, VarFinalInsts1), + map__apply_to_list(HeadVars, VarTypes, ArgTypes), ( InferModes = yes -> - normalise_insts(VarFinalInsts1, ModuleInfo, VarFinalInsts2), + normalise_insts(VarFinalInsts1, ArgTypes, ModuleInfo, + VarFinalInsts2), % % make sure we set the final insts of any variables which % we assumed were dead to `clobbered'. @@ -995,10 +1035,19 @@ modecheck_goal_expr(if_then_else(Vs, A0, B0, C0, SM), GoalInfo0, Goal) --> mode_info_lock_vars(if_then_else, NonLocals), mode_info_add_live_vars(B_Vars), modecheck_goal(A0, A), + mode_info_dcg_get_instmap(InstMapA), mode_info_remove_live_vars(B_Vars), mode_info_unlock_vars(if_then_else, NonLocals), - modecheck_goal(B0, B), - mode_info_dcg_get_instmap(InstMapB), + ( { instmap__is_reachable(InstMapA) } -> + modecheck_goal(B0, B), + mode_info_dcg_get_instmap(InstMapB) + ; + % We should not mode-analyse the goal, since it is unreachable. + % Instead we optimize the goal away, so that later passes + % won't complain about it not having mode information. + { true_goal(B) }, + { InstMapB = InstMapA } + ), mode_info_set_instmap(InstMap0), modecheck_goal(C0, C), mode_info_dcg_get_instmap(InstMapC), @@ -1024,7 +1073,9 @@ modecheck_goal_expr(some(Vs, G0), _, some(Vs, G)) --> modecheck_goal_expr(call(PredId, ProcId0, Args0, _, Context, PredName), GoalInfo0, Goal) --> - mode_checkpoint(enter, "call"), + { prog_out__sym_name_to_string(PredName, PredNameString) }, + { string__append("call ", PredNameString, CallString) }, + mode_checkpoint(enter, CallString), mode_info_set_call_context(call(PredId)), =(ModeInfo0), { mode_info_get_instmap(ModeInfo0, InstMap0) }, @@ -1041,7 +1092,7 @@ modecheck_goal_expr(call(PredId, ProcId0, Args0, _, Context, PredName), InstMap0, Goal), mode_info_unset_call_context, - mode_checkpoint(exit, "call"). + mode_checkpoint(exit, CallString). modecheck_goal_expr(higher_order_call(PredVar, Args0, _, _, _, PredOrFunc), GoalInfo0, Goal) --> @@ -1233,7 +1284,17 @@ modecheck_conj_list_no_delay([Goal0 | Goals0], [Goal | Goals]) --> { goal_get_nonlocals(Goal0, NonLocals) }, mode_info_remove_live_vars(NonLocals), modecheck_goal(Goal0, Goal), - modecheck_conj_list_no_delay(Goals0, Goals). + mode_info_dcg_get_instmap(InstMap), + ( { instmap__is_unreachable(InstMap) } -> + % We should not mode-analyse the remaining goals, since they + % are unreachable. Instead we optimize them away, so that + % later passes won't complain about them not having mode + % information. + mode_info_remove_goals_live_vars(Goals0), + { Goals = [] } + ; + modecheck_conj_list_no_delay(Goals0, Goals) + ). %-----------------------------------------------------------------------------% @@ -1391,6 +1452,10 @@ modecheck_conj_list_2([Goal0 | Goals0], ImpurityErrors0, mode_info_set_delay_info(DelayInfo), mode_info_dcg_get_instmap(InstMap), ( { instmap__is_unreachable(InstMap) } -> + % We should not mode-analyse the remaining goals, since they + % are unreachable. Instead we optimize them away, so that + % later passes won't complain about them not having mode + % information. mode_info_remove_goals_live_vars(Goals1), { Goals2 = [] }, { ImpurityErrors = ImpurityErrors2 } @@ -1428,7 +1493,7 @@ check_for_impurity_error(Goal, ImpurityErrors0, ImpurityErrors) --> { mode_info_get_predid(ModeInfo0, PredId) }, { module_info_pred_info(ModuleInfo, PredId, PredInfo) }, { pred_info_clauses_info(PredInfo, ClausesInfo) }, - { ClausesInfo = clauses_info(_,_,_,HeadVars,_) }, + { clauses_info_headvars(ClausesInfo, HeadVars) }, ( { no_non_headvar_unification_goals(DelayedGoals, HeadVars) } -> { ImpurityErrors = ImpurityErrors0 } ; @@ -1521,10 +1586,22 @@ modecheck_case_list([Case0 | Cases0], Var, modecheck_set_var_inst(Var, bound(unique, [functor(ConsId, ArgInsts)])), - modecheck_goal(Goal0, Goal1), - mode_info_dcg_get_instmap(InstMap), + % modecheck this case (if it is reachable) + mode_info_dcg_get_instmap(InstMap1), + ( { instmap__is_reachable(InstMap1) } -> + modecheck_goal(Goal0, Goal1), + mode_info_dcg_get_instmap(InstMap) + ; + % We should not mode-analyse the goal, since it is unreachable. + % Instead we optimize the goal away, so that later passes + % won't complain about it not having mode information. + { true_goal(Goal1) }, + { InstMap = InstMap1 } + ), + % Don't lose the information added by the functor test above. { fixup_switch_var(Var, InstMap0, InstMap, Goal1, Goal) }, + mode_info_set_instmap(InstMap0), modecheck_case_list(Cases0, Var, Cases, InstMaps). @@ -1582,6 +1659,21 @@ get_all_conjunct_nonlocals([G|Gs], NonLocals0, NonLocals) :- get_all_conjunct_nonlocals(Gs, NonLocals1, NonLocals). +%-----------------------------------------------------------------------------% + + % + % calculate the argument number offset that needs to be passed to + % modecheck_var_list_is_live, modecheck_var_has_inst_list, and + % modecheck_set_var_inst_list. This offset number is calculated + % so that real arguments get positive argument numbers and + % type_info arguments get argument numbers less than or equal to 0. + % +compute_arg_offset(PredInfo, ArgOffset) :- + pred_info_arity(PredInfo, OrigArity), + pred_info_arg_types(PredInfo, ArgTypes), + list__length(ArgTypes, CurrentArity), + ArgOffset = OrigArity - CurrentArity. + %-----------------------------------------------------------------------------% % Given a list of variables and a list of expected livenesses, @@ -1655,10 +1747,11 @@ modecheck_var_has_inst(VarId, Inst, ModeInfo0, ModeInfo) :- %-----------------------------------------------------------------------------% -modecheck_set_var_inst_list(Vars0, InitialInsts, FinalInsts, Vars, Goals) --> +modecheck_set_var_inst_list(Vars0, InitialInsts, FinalInsts, ArgOffset, + Vars, Goals) --> ( modecheck_set_var_inst_list_2(Vars0, InitialInsts, FinalInsts, - no_extra_goals, 0, Vars1, Goals1) + no_extra_goals, ArgOffset, Vars1, Goals1) -> { Vars = Vars1, Goals = Goals1 } ; @@ -1915,7 +2008,7 @@ handle_implied_mode(Var0, VarInst0, InitialInst0, Var, % Construct the code to do the unification modecheck_unify__create_var_var_unification(Var0, Var, - ModeInfo, ExtraGoal), + VarType, ModeInfo, ExtraGoal), % append the goals together in the appropriate order: % ExtraGoals0, then NewUnify diff --git a/compiler/notes/compiler_design.html b/compiler/notes/compiler_design.html index 1c3496715..8aa76c6b5 100644 --- a/compiler/notes/compiler_design.html +++ b/compiler/notes/compiler_design.html @@ -258,9 +258,30 @@ so that the compiler does the right thing for options such as operations on it. It also calls post_typecheck.m to complete the handling of predicate overloading for cases which typecheck.m is unable to handle, - to check for unbound type variables, - and to copy the clauses to the proc_infos in - preparation for mode analysis. + and to check for unbound type variables. + +
+ This phase also converts function calls into predicate calls, + converts higher-order predicate terms into lambda expressions, + and copies the clauses to the proc_infos in preparation for + mode analysis. +
+ The polymorphism.m module also exports some utility routines that + are used by other modules. These include some routines for generating + code to create type_infos, which are used by simplify.m and magic.m + when those modules introduce new calls to polymorphic procedures.
@@ -354,12 +374,13 @@ so that the compiler does the right thing for options such as that they should not have been included in the program in the first place. (That's why this pass needs to be part of semantic analysis: because it can report warnings.) + simplify.m converts complicated unifications into procedure calls. simplify.m calls common.m which looks for (a) construction unifications that construct a term that is the same as one that already exists, or (b) repeated calls to a predicate with the same inputs, and replaces them with assignment unifications. simplify.m also attempts to partially evaluate calls to builtin - procedures if the inputs are all constants (see const_prop.m). + procedures if the inputs are all constants (see const_prop.m), @@ -373,17 +394,11 @@ defined in mercury_builtin.m and the addition of some scaffolding structure.
-The next two passes of this stage are code simplifications. +The next pass of this stage is a code simplification, namely +removal of lambda expressions (lambda.m):
- +
- -To improve efficiency, the above two passes are actually combined into -one - polymorphism.m calls calls lambda__transform_lambda directly. +(Is there any good reason why lambda.m comes after table_gen.m?)
@@ -927,6 +939,6 @@ Some of them are obsolete; other are work-in-progress.