diff --git a/compiler/mercury_compile_front_end.m b/compiler/mercury_compile_front_end.m index 08567e01c..02ba5ede8 100644 --- a/compiler/mercury_compile_front_end.m +++ b/compiler/mercury_compile_front_end.m @@ -157,7 +157,6 @@ :- import_module transform_hlds.intermod_mark_exported. :- import_module benchmarking. -:- import_module int. :- import_module map. :- import_module pair. :- import_module require. @@ -169,7 +168,7 @@ %---------------------------------------------------------------------------% frontend_pass(ProgressStream, ErrorStream, OpModeAugment, QualInfo0, - FoundUndefModeError, !FoundError, + InvalidInstModeSpecs, !FoundError, !HLDS, !DumpInfo, !MaybeWrittenSpecs, !IO) :- module_info_get_globals(!.HLDS, Globals), % It would be nice to move the decide_type_repns pass later, possibly @@ -189,11 +188,11 @@ frontend_pass(ProgressStream, ErrorStream, OpModeAugment, QualInfo0, "% Checking typeclasses...\n", !IO), check_typeclasses(ProgressStream, !HLDS, QualInfo0, QualInfo, TypeClassSpecs), - TypeClassErrors = contains_errors(Globals, TypeClassSpecs), add_to_be_written_specs(TypeClassSpecs, !MaybeWrittenSpecs), maybe_dump_hlds(ProgressStream, !.HLDS, 5, "typeclass", !DumpInfo, !IO), set_module_recompilation_info(QualInfo, !HLDS), + TypeClassErrors = contains_errors(Globals, TypeClassSpecs), ( TypeClassErrors = yes, % We can't continue after a typeclass error, because if we did, @@ -202,7 +201,7 @@ frontend_pass(ProgressStream, ErrorStream, OpModeAugment, QualInfo0, ; TypeClassErrors = no, frontend_pass_after_typeclass_check(ProgressStream, ErrorStream, - OpModeAugment, FoundUndefModeError, !FoundError, + OpModeAugment, InvalidInstModeSpecs, !FoundError, !HLDS, !DumpInfo, !MaybeWrittenSpecs, !IO) ). @@ -224,7 +223,7 @@ frontend_pass_after_typeclass_check(ProgressStream, ErrorStream, OpModeAugment, check_insts_for_matching_types(ProgressStream, ErrorStream, Verbose, Stats, Globals, !HLDS, !DumpInfo, !MaybeWrittenSpecs, !IO), do_typecheck(ProgressStream, ErrorStream, Verbose, Stats, Globals, - FoundSyntaxError, FoundTypeError, DidWeExceedIterationLimit, + FoundSyntaxError, TypeCheckSpecs, NumIterations, !HLDS, !DumpInfo, !MaybeWrittenSpecs, !IO), % We can't continue after an undefined inst/mode error, since @@ -241,29 +240,24 @@ frontend_pass_after_typeclass_check(ProgressStream, ErrorStream, OpModeAugment, "% Program contains undefined inst or undefined mode error(s).\n", !IO), io.set_exit_status(1, !IO) - else if DidWeExceedIterationLimit = exceeded_iteration_limit then - % FoundTypeError will always be true here, so if Verbose = yes, - % we have already printed a message about the program containing - % type errors. + else if NumIterations = exceeded_iteration_limit(_LimitSpec) then + % TypeCheckSpecs will always contain diagnostics here, so if + % Verbose = yes, we have already printed those diagnostics, + % which will also report the breaching of the iteration limit. !:FoundError = yes, io.set_exit_status(1, !IO) else check_for_missing_type_defns(!.HLDS, MissingTypeDefnSpecs), add_to_be_written_specs(MissingTypeDefnSpecs, !MaybeWrittenSpecs), - SomeMissingTypeDefns = contains_errors(Globals, MissingTypeDefnSpecs), pretest_user_inst_table(!HLDS), - post_typecheck_finish_preds(!HLDS, NumPostTypeCheckErrors, + post_typecheck_finish_preds(!HLDS, UnprovenConstraintSpecs, PostTypeCheckAlwaysSpecs, PostTypeCheckNoTypeErrorSpecs), - io.get_exit_status(ExitStatus, !IO), SpecsSoFar = maybe_written_specs_to_specs(!.MaybeWrittenSpecs), - MaybeWorstSeverity = worst_severity_in_specs(Globals, SpecsSoFar), - ( if - ( ExitStatus \= 0 - ; MaybeWorstSeverity = yes(actual_severity_error) - ) - then + ErrorsSoFar = contains_errors(Globals, SpecsSoFar), + ( + ErrorsSoFar = yes % If the module contains errors, then generating warnings % about unused types would have two problems. % @@ -287,8 +281,8 @@ frontend_pass_after_typeclass_check(ProgressStream, ErrorStream, OpModeAugment, % fixed. Since the code of unused_types.m cannot possibly predict % what the fixed version would look like, it is best not to % invoke it during *this* compiler invocation. - true - else + ; + ErrorsSoFar = no, warn_about_unused_types(!.HLDS, [], UnusedTypeSpecs), add_to_be_written_specs(UnusedTypeSpecs, !MaybeWrittenSpecs) ), @@ -300,19 +294,22 @@ frontend_pass_after_typeclass_check(ProgressStream, ErrorStream, OpModeAugment, % PostTypeCheckNoTypeErrorSpecs, and we report them only if % we did not find any errors during typecheck. add_to_be_written_specs(PostTypeCheckAlwaysSpecs, !MaybeWrittenSpecs), + TypeCheckErrors = contains_errors(Globals, TypeCheckSpecs), ( - FoundTypeError = no, + TypeCheckErrors = no, + add_to_be_written_specs(UnprovenConstraintSpecs, + !MaybeWrittenSpecs), add_to_be_written_specs(PostTypeCheckNoTypeErrorSpecs, !MaybeWrittenSpecs) ; - FoundTypeError = yes + TypeCheckErrors = yes ), ( if - ( FoundTypeError = yes - ; FoundSyntaxError = some_clause_syntax_errors - ; SomeMissingTypeDefns = yes - ; NumPostTypeCheckErrors > 0 + ( FoundSyntaxError = some_clause_syntax_errors + ; TypeCheckErrors = yes + ; contains_errors(Globals, MissingTypeDefnSpecs) = yes + ; contains_errors(Globals, UnprovenConstraintSpecs) = yes ) then % XXX It would be nice if we could go on and mode-check the @@ -390,13 +387,13 @@ check_insts_for_matching_types(ProgressStream, ErrorStream, Verbose, Stats, "warn_insts_without_matching_type", !DumpInfo, !IO). :- pred do_typecheck(io.text_output_stream::in, io.text_output_stream::in, - bool::in, bool::in, globals::in, - maybe_clause_syntax_errors::out, bool::out, number_of_iterations::out, + bool::in, bool::in, globals::in, maybe_clause_syntax_errors::out, + list(error_spec)::out, number_of_iterations::out, module_info::in, module_info::out, dump_info::in, dump_info::out, maybe_written_specs::in, maybe_written_specs::out, io::di, io::uo) is det. do_typecheck(ProgressStream, ErrorStream, Verbose, Stats, Globals, - FoundSyntaxError, FoundTypeError, DidWeExceedIterationLimit, + FoundSyntaxError, TypeCheckSpecs, NumIterations, !HLDS, !DumpInfo, !MaybeWrittenSpecs, !IO) :- % Next typecheck the clauses. maybe_write_not_yet_written_specs(ErrorStream, Globals, Verbose, @@ -417,7 +414,7 @@ do_typecheck(ProgressStream, ErrorStream, Verbose, Stats, Globals, ), % XXX We should teach typecheck_constraints to report syntax errors. FoundSyntaxError = no_clause_syntax_errors, - DidWeExceedIterationLimit = within_iteration_limit + NumIterations = within_iteration_limit ; TypeCheckUsingConstraints = no, prepare_for_typecheck_module(!HLDS, [], PrepareSpecs), @@ -427,7 +424,7 @@ do_typecheck(ProgressStream, ErrorStream, Verbose, Stats, Globals, maybe_dump_hlds(ProgressStream, !.HLDS, 14, "pre_typecheck", !DumpInfo, !IO), typecheck_module(ProgressStream, !HLDS, TypeCheckSpecs, - FoundSyntaxError, DidWeExceedIterationLimit) + FoundSyntaxError, NumIterations) ), add_to_be_written_specs(TypeCheckSpecs, !MaybeWrittenSpecs), maybe_write_not_yet_written_specs(ErrorStream, Globals, Verbose, diff --git a/compiler/post_typecheck.m b/compiler/post_typecheck.m index fa9c6247c..737b1a2f0 100644 --- a/compiler/post_typecheck.m +++ b/compiler/post_typecheck.m @@ -41,7 +41,7 @@ %---------------------------------------------------------------------------% - % post_typecheck_finish_preds(!ModuleInfo, NumErrors, + % post_typecheck_finish_preds(!ModuleInfo, UnprovenConstraintSpecs, % AlwaysSpecs, NoTypeErrorSpecs): % % Check that the types of variables in predicates contain no unbound type @@ -49,22 +49,25 @@ % head variables, and that there are no unsatisfied type class constraints. % Also bind any unbound type variables to the type `void'. % - % Return two lists of error messages. AlwaysSpecs will be the messages - % we want to print in all cases, and NoTypeErrorSpecs will be the messages - % we want to print only if type checking did not find any errors. The - % latter will be the kinds of errors that you can get as "avalanche" - % messages from type errors. + % Return three lists of error messages. % - % Separately, we return NumBadErrors, the number of errors that prevent us - % from proceeding further in compilation. We do this separately since some - % errors (e.g. bad type for main) do NOT prevent us from going further. + % The first, UnprovenConstraintSpecs, reports the errors that + % prevent us from proceeding further in compilation. Errors in the + % next two lists do not do this. + % + % AlwaysSpecs will be the messages we want to print in all cases, + % while NoTypeErrorSpecs will be the messages we want to print + % only if type checking did not find any errors. The latter will be + % the kinds of errors that you can get as "avalanche" messages + % from type errors. % % Note that when checking assertions, we take the conservative approach % of warning about unbound type variables. There may be cases for which % this doesn't make sense. % :- pred post_typecheck_finish_preds(module_info::in, module_info::out, - int::out, list(error_spec)::out, list(error_spec)::out) is det. + list(error_spec)::out, list(error_spec)::out, list(error_spec)::out) + is det. % Make sure the vartypes field in the clauses_info is valid for imported % predicates. (Non-imported predicates should already have it set up.) @@ -122,47 +125,52 @@ %---------------------------------------------------------------------------% -post_typecheck_finish_preds(!ModuleInfo, NumBadErrors, +post_typecheck_finish_preds(!ModuleInfo, UnprovenConstraintSpecs, AlwaysSpecs, NoTypeErrorSpecs) :- module_info_get_valid_pred_ids(!.ModuleInfo, ValidPredIds), ValidPredIdSet = set_tree234.list_to_set(ValidPredIds), module_info_get_pred_id_table(!.ModuleInfo, PredIdTable0), map.to_sorted_assoc_list(PredIdTable0, PredIdsInfos0), post_typecheck_do_finish_preds(!.ModuleInfo, ValidPredIdSet, - PredIdsInfos0, PredIdsInfos, map.init, _TypePropCache, 0, NumBadErrors, - [], AlwaysSpecs, [], NoTypeErrorSpecs), + PredIdsInfos0, PredIdsInfos, map.init, _TypePropCache, + [], UnprovenConstraintSpecs, [], AlwaysSpecs, [], NoTypeErrorSpecs), map.from_sorted_assoc_list(PredIdsInfos, PredIdTable), module_info_set_pred_id_table(PredIdTable, !ModuleInfo). :- pred post_typecheck_do_finish_preds(module_info::in, set_tree234(pred_id)::in, assoc_list(pred_id, pred_info)::in, assoc_list(pred_id, pred_info)::out, - tprop_cache::in, tprop_cache::out, int::in, int::out, + tprop_cache::in, tprop_cache::out, + list(error_spec)::in, list(error_spec)::out, list(error_spec)::in, list(error_spec)::out, list(error_spec)::in, list(error_spec)::out) is det. post_typecheck_do_finish_preds(_ModuleInfo, _ValidPredIdSet, [], [], - !TypePropCache, !NumBadErrors, !AlwaysSpecs, !NoTypeErrorSpecs). + !TypePropCache, + !UnprovenConstraintSpecs, !AlwaysSpecs, !NoTypeErrorSpecs). post_typecheck_do_finish_preds(ModuleInfo, ValidPredIdSet, [PredIdInfo0 | PredIdsInfos0], [PredIdInfo | PredIdsInfos], - !TypePropCache, !NumBadErrors, !AlwaysSpecs, !NoTypeErrorSpecs) :- + !TypePropCache, + !UnprovenConstraintSpecs, !AlwaysSpecs, !NoTypeErrorSpecs) :- PredIdInfo0 = PredId - PredInfo0, post_typecheck_do_finish_pred(ModuleInfo, ValidPredIdSet, - PredId, PredInfo0, PredInfo, - !TypePropCache, !NumBadErrors, !AlwaysSpecs, !NoTypeErrorSpecs), + PredId, PredInfo0, PredInfo, !TypePropCache, + !UnprovenConstraintSpecs, !AlwaysSpecs, !NoTypeErrorSpecs), PredIdInfo = PredId - PredInfo, post_typecheck_do_finish_preds(ModuleInfo, ValidPredIdSet, - PredIdsInfos0, PredIdsInfos, - !TypePropCache, !NumBadErrors, !AlwaysSpecs, !NoTypeErrorSpecs). + PredIdsInfos0, PredIdsInfos, !TypePropCache, + !UnprovenConstraintSpecs, !AlwaysSpecs, !NoTypeErrorSpecs). :- pred post_typecheck_do_finish_pred(module_info::in, set_tree234(pred_id)::in, pred_id::in, pred_info::in, pred_info::out, - tprop_cache::in, tprop_cache::out, int::in, int::out, + tprop_cache::in, tprop_cache::out, + list(error_spec)::in, list(error_spec)::out, list(error_spec)::in, list(error_spec)::out, list(error_spec)::in, list(error_spec)::out) is det. -post_typecheck_do_finish_pred(ModuleInfo, ValidPredIdSet, PredId, !PredInfo, - !TypePropCache, !NumBadErrors, !AlwaysSpecs, !NoTypeErrorSpecs) :- +post_typecheck_do_finish_pred(ModuleInfo, ValidPredIdSet, PredId, + !PredInfo, !TypePropCache, + !UnprovenConstraintSpecs, !AlwaysSpecs, !NoTypeErrorSpecs) :- ( if set_tree234.contains(ValidPredIdSet, PredId) then % Regardless of the path we take when processing a valid predicate, % we need to ensure that we fill in the vte_is_dummy field in all @@ -195,7 +203,7 @@ post_typecheck_do_finish_pred(ModuleInfo, ValidPredIdSet, PredId, !PredInfo, pred_info_set_clauses_info(ClausesInfo, !PredInfo), find_unproven_body_constraints(ModuleInfo, PredId, !.PredInfo, - !NumBadErrors, !NoTypeErrorSpecs), + !UnprovenConstraintSpecs), find_unresolved_types_fill_in_is_dummy_in_pred(ModuleInfo, PredId, !PredInfo, !NoTypeErrorSpecs), check_type_of_main(!.PredInfo, !AlwaysSpecs) @@ -268,21 +276,20 @@ report_unbound_inst_var_error(ModuleInfo, PredId, ProcId - UnboundInstVars, % other than those that occur in the types of head variables, and that % there are no unsatisfied type class constraints. % -:- pred find_unproven_body_constraints(module_info::in, pred_id::in, - pred_info::in, int::in, int::out, +:- pred find_unproven_body_constraints(module_info::in, + pred_id::in, pred_info::in, list(error_spec)::in, list(error_spec)::out) is det. -:- pragma inline(pred(find_unproven_body_constraints/7)). +:- pragma inline(pred(find_unproven_body_constraints/5)). find_unproven_body_constraints(ModuleInfo, PredId, PredInfo, - !NumBadErrors, !NoTypeErrorSpecs) :- + !UnprovenConstraintSpecs) :- pred_info_get_unproven_body_constraints(PredInfo, UnprovenConstraints0), ( UnprovenConstraints0 = [_ | _], list.sort_and_remove_dups(UnprovenConstraints0, UnprovenConstraints), - report_unsatisfied_constraints(ModuleInfo, PredId, PredInfo, - UnprovenConstraints, !NoTypeErrorSpecs), - list.length(UnprovenConstraints, NumUnprovenConstraints), - !:NumBadErrors = !.NumBadErrors + NumUnprovenConstraints + Spec = report_unsatisfied_constraints(ModuleInfo, PredId, PredInfo, + UnprovenConstraints), + !:UnprovenConstraintSpecs = [Spec | !.UnprovenConstraintSpecs] ; UnprovenConstraints0 = [] ). @@ -291,12 +298,11 @@ find_unproven_body_constraints(ModuleInfo, PredId, PredInfo, % Report unsatisfied typeclass constraints. % -:- pred report_unsatisfied_constraints(module_info::in, - pred_id::in, pred_info::in, list(prog_constraint)::in, - list(error_spec)::in, list(error_spec)::out) is det. +:- func report_unsatisfied_constraints(module_info, pred_id, pred_info, + list(prog_constraint)) = error_spec. -report_unsatisfied_constraints(ModuleInfo, PredId, PredInfo, Constraints, - !Specs) :- +report_unsatisfied_constraints(ModuleInfo, PredId, PredInfo, Constraints) + = Spec :- pred_info_get_typevarset(PredInfo, TVarSet), pred_info_get_context(PredInfo, Context), @@ -335,8 +341,7 @@ report_unsatisfied_constraints(ModuleInfo, PredId, PredInfo, Constraints, ContextMsgs = [ContextMsgsPrefix | ContextMsgsList] ), Spec = error_spec($pred, severity_error, phase_type_check, - [MainMsg | ContextMsgs]), - !:Specs = [Spec | !.Specs]. + [MainMsg | ContextMsgs]). :- func constraint_to_error_pieces(tvarset, prog_constraint) = list(format_piece). diff --git a/compiler/typecheck.m b/compiler/typecheck.m index be369c77f..bd6b48085 100644 --- a/compiler/typecheck.m +++ b/compiler/typecheck.m @@ -85,7 +85,10 @@ :- type number_of_iterations ---> within_iteration_limit - ; exceeded_iteration_limit. + ; exceeded_iteration_limit(error_spec). + % This error_spec reprorting the breaching of the iteration limit + % will have been also returned as an element of Specs + % in typecheck_module's argument list. % typecheck_module(ProgressStream, !ModuleInfo, Specs, FoundSyntaxError, % NumberOfIterations): @@ -239,9 +242,10 @@ typecheck_to_fixpoint(ProgressStream, Iteration, MaxIterations, !ModuleInfo, FoundSyntaxError, NumberOfIterations) else FinalValidPredIdSet = NewValidPredIdSet, - Specs = [typecheck_report_max_iterations_exceeded(MaxIterations)], FoundSyntaxError = CurFoundSyntaxError, - NumberOfIterations = exceeded_iteration_limit + Spec = typecheck_report_max_iterations_exceeded(MaxIterations), + Specs = [Spec], + NumberOfIterations = exceeded_iteration_limit(Spec) ) ).