<div dir="ltr"><div dir="ltr"><br></div><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Fri, 17 Jul 2026 at 10:32, Zoltan Somogyi <<a href="mailto:zoltan.somogyi@runbox.com">zoltan.somogyi@runbox.com</a>> wrote:</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
The diff is huge and boring. </blockquote><div><br></div><div>Yes.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The only parts I am seeking feedback on<br>
are the parts marked by "XXX DIAG_SPEC" and a comment. The parts<br>
marked by "XXX DIAG_SPEC" without a new comment are reminders<br>
to myself about minor changes to do after this diff is committed.</blockquote><div><br></div><div>> Use {err,warn,info}_spec as subtypes of diag_spec ...<br><br>...<br><br>> compiler/superhomogeneous_lambda.m:<br>> Return one (or more) of {err,warn,info}_specs instead of<br>> diag_specs. Perform the same replacements in data structures.<br>> (In most modules, diag_specs are replaced by *only* err_specs.)<br>> <br>> In modules where the diag_specs have all been replaced<br>> by the same subtype, keep using Specs as (part of) the names<br>> of the variables containing them. In modules that use<br>> more than one of the new subtypes, use ErrSpecs, WarnSpecs<br>> and/or InfoSpecs.<br>> <br>> Consistenly put err_specs before warn_specs, and both<br>> before info_specs.<br><br>s/Consistenly/Consistently/<br><br>...<br><br><br>> diff --git a/compiler/add_pragma_util.m b/compiler/add_pragma_util.m<br>> index 2d1a1f336..c61b80635 100644<br>> --- a/compiler/add_pragma_util.m<br>> +++ b/compiler/add_pragma_util.m<br><br>...<br><br><br>> @@ -295,10 +292,13 @@ look_up_pragma_pf_sym_arity(ModuleInfo, IsFullyQualified, FailHandling,<br>> Specs = []<br>> ;<br>> InformIgnored = yes,<br>> - Severity =<br>> - severity_informational(inform_ignored_pragma_errors),<br>> - Spec = report_ambiguous_pred_or_func(Severity, PragmaName,<br>> - Context, PredOrFunc, SymName, UserArity),<br>> + % XXX DIAG_SPEC<br>> + % This Spec used to have this severity:<br>> + % Severity =<br>> + % severity_informational(inform_ignored_pragma_errors),<br>> + % Should it stay that way?<br>> + Spec = report_ambiguous_pred_or_func(PragmaName, Context,<br>> + PredOrFunc, SymName, UserArity),<br>> Specs = [Spec]<br><br><br>Strictly speaking, unrecognised pragmas should be ignored. Practically, since<br>there is only one Mercury implementation, it's probably better to treat them<br>as errors.<br><br>...<br><br>> diff --git a/compiler/check_module_interface.m b/compiler/check_module_interface.m<br>> index 500110a36..b765b69e2 100644<br>> --- a/compiler/check_module_interface.m<br>> +++ b/compiler/check_module_interface.m<br>> @@ -30,7 +30,7 @@<br>> % report a warning.<br>> %<br>> :- pred check_module_interface_for_no_exports(globals::in,<br>> - parse_tree_module_src::in, list(diag_spec)::out) is det.<br>> + parse_tree_module_src::in, list(warn_spec)::out) is det.<br>> <br>> %---------------------------------------------------------------------------%<br>> %---------------------------------------------------------------------------%<br>> @@ -63,7 +63,7 @@ check_module_interface_for_no_exports(Globals, ParseTreeModuleSrc, Specs) :-<br>> _IntFIMs, _ImpFIMs, _IntSelfFIMLangs, _ImpSelfFIMLangs,<br>> <br>> TypeCtorCheckedMap, InstCtorCheckedMap, ModeCtorCheckedMap,<br>> - TypeSpecs, InstModeSpecs,<br>> + TypeErrSpecs, TypeWarnSpecs, InstModeErrSpecs, InstModeWarnSpecs,<br>> <br>> IntTypeClasses, IntInstances, IntPredDecls, IntModeDecls,<br>> IntDeclPragmas, IntDeclMarkers, IntPromises, _IntBadClauses,<br>> @@ -133,8 +133,15 @@ check_module_interface_for_no_exports(Globals, ParseTreeModuleSrc, Specs) :-<br>> % a "no exports" warning or not. This means that the warning<br>> % is not really needed *now*; it can be generated later,<br>> % once the complained-about invalid definitions are fixed.<br>> - TypeSpecs = [],<br>> - InstModeSpecs = [],<br>> + TypeErrSpecs = [],<br>> + InstModeErrSpecs = [],<br>> +<br>> + % XXX DIAG_SPECS<br>> + % These two conditions preserve existing behavior, from a time<br>> + % where the parse tree stored co-mingled diag_specs. but<br>> + % I (zs) don't think it should be preserved.<br><br><br>I don't think it's worth preserving the old behaviour here.<br><br>...<br><br>> diff --git a/compiler/grab_modules.m b/compiler/grab_modules.m<br>> index b65725ec7..442c9c946 100644<br>> --- a/compiler/grab_modules.m<br>> +++ b/compiler/grab_modules.m<br><br>...<br><br><br>> @@ -725,10 +724,11 @@ grab_trans_opt_files(ProgressStream, Globals, TransOptModuleNames,<br>> <br>> read_trans_opt_files(ProgressStream, Globals, TransOptModuleNames,<br>> cord.init, ParseTreeTransOptsCord,<br>> - [], NonBlockingSpecs, [], BlockingSpecs, !IO),<br>> + [], BlockErrSpecs, [], WarnSpecs, !IO),<br>> list.foldl(aug_compilation_unit_add_trans_opt,<br>> cord.list(ParseTreeTransOptsCord), !AugCompUnit),<br>> - module_baggage_add_nonfatal_specs(NonBlockingSpecs, !Baggage),<br>> + % XXX DIAG_SPECS We used to call module_baggage_add_nonfatal_specs.<br>> + module_baggage_add_warnings(WarnSpecs, !Baggage),<br><br>Looking at the nonfatal errors we have rme_unexpected_term_in_int_or_opt,<br>which seems relevant to reading .trans_opt files.<br><br>> % XXX why ignore any existing errors?<br>> !Baggage ^ mb_errors := init_read_module_errors,<br>> <br><br>...<br><br><br>> diff --git a/compiler/make_hlds_passes.m b/compiler/make_hlds_passes.m<br>> index bee01e019..67bc39850 100644<br>> --- a/compiler/make_hlds_passes.m<br>> +++ b/compiler/make_hlds_passes.m<br><br>...<br><br>> @@ -698,7 +707,9 @@ maybe_warn_include_and_non_include(Globals, ParseTreeModuleSrc, Specs) :-<br>> words("Moving those entities to other modules can reduce"),<br>> words("the number of modules needing to be recompiled"),<br>> words("after a change."), nl],<br>> - Spec = spec($pred, severity_error, phase_pt2h, Context, Pieces),<br>> + % XXX DIAG_SPECS The severity used to be error.<br>> + Severity = severity_warning(warn_include_and_non_include),<br>> + Spec = spec($pred, Severity, phase_pt2h, Context, Pieces),<br>> Specs = [Spec]<br>> else<br>> Specs = []<br><br>The old behaviour was surely a mistake. The message says that this is a<br>warning, as does the name of this predicate.<br><br><br>> diff --git a/compiler/maybe_error.m b/compiler/maybe_error.m<br>> index 540e72d35..f62eb3f76 100644<br>> --- a/compiler/maybe_error.m<br>> +++ b/compiler/maybe_error.m<br><br>...<br><br><br>> @@ -106,36 +111,79 @@<br>> <br>> %---------------------%<br>> <br>> -:- func get_any_errors1(maybe1(T1)) = list(diag_spec).<br>> -:- func get_any_errors2(maybe2(T1, T2)) = list(diag_spec).<br>> -:- func get_any_errors3(maybe3(T1, T2, T3)) = list(diag_spec).<br>> -:- func get_any_errors4(maybe4(T1, T2, T3, T4)) = list(diag_spec).<br>> -:- func get_any_errors5(maybe5(T1, T2, T3, T4, T5)) = list(diag_spec).<br>> -:- func get_any_errors6(maybe6(T1, T2, T3, T4, T5, T6)) = list(diag_spec).<br>> + % This type, which is used mostly by code that parses goals,<br>> + % allows us to record both<br>> + % - the presence of at least one error, and<br>> + % - the presence of zero or more warnings.<br>> + % The reason why we use tuples is that any readable function symbol<br>> + % we could use would make the lines that construct errors too long.<br>> +:- type err_warn_error == {one_or_more(err_spec), list(warn_spec)}.<br>> <br>> -:- func get_any_errors1el(maybe1el(T1)) = list(diag_spec).<br>> -:- func get_any_errors2el(maybe2el(T1, T2)) = list(diag_spec).<br>> -:- func get_any_errors3el(maybe3el(T1, T2, T3)) = list(diag_spec).<br>> -:- func get_any_errors4el(maybe4el(T1, T2, T3, T4)) = list(diag_spec).<br>> -:- func get_any_errors5el(maybe5el(T1, T2, T3, T4, T5)) = list(diag_spec).<br>> -:- func get_any_errors6el(maybe6el(T1, T2, T3, T4, T5, T6)) = list(diag_spec).<br>> +% XXX DIAG_SPECS<br>> +% The numbers in these names mirror the number of arguments of the okN<br>> +% function symbol, but they do not match the type constructor's arity,<br>> +% due to the warn_specs being implicit. Which is more important?<br><br>I would say the latter.<br><br>> +:- type parse_result2(T) ==<br>> + maybe2(T, list(warn_spec), err_warn_error).<br>> +:- type parse_result3(T1, T2) ==<br>> + maybe3(T1, T2, list(warn_spec), err_warn_error).<br>> +:- type parse_result4(T1, T2, T3) ==<br>> + maybe4(T1, T2, T3, list(warn_spec), err_warn_error).<br>> <br><br>...<br><br><br>> diff --git a/compiler/mercury_compile_args.m b/compiler/mercury_compile_args.m<br>> index 8e53f54f1..a3c0bd2f6 100644<br>> --- a/compiler/mercury_compile_args.m<br>> +++ b/compiler/mercury_compile_args.m<br><br><br>...<br><br>> @@ -286,34 +288,37 @@ process_options_std(ProgressStream, DefaultOptionTable, CmdLineArgs,<br>> DefaultOptionTable, ArgsOptionTable, cord.init, _UserData, !IO),<br>> (<br>> MaybeError = yes(OptionError),<br>> - Specs = report_option_error(OptionError),<br>> - Result = opr_failure(Specs)<br>> + OoMErrSpecs = report_option_error(OptionError),<br>> + Result = opr_failure(OoMErrSpecs, [])<br>> ;<br>> MaybeError = no,<br>> read_options_files_named_in_options_file_option(ProgressStream,<br>> ArgsOptionTable, EnvOptFileVariables0,<br>> - OptFileNonUndefSpecs, OptFileUndefSpecs, !IO),<br>> + OptFileErrSpecs, OptFileUndefWarnSpecs0, !IO),<br>> getopt.lookup_bool_option(ArgsOptionTable,<br>> warn_undefined_options_variables, WarnUndef),<br>> (<br>> WarnUndef = no,<br>> - OptFileSpecs = OptFileNonUndefSpecs<br>> + OptFileUndefWarnSpecs = []<br>> ;<br>> WarnUndef = yes,<br>> - OptFileSpecs = OptFileNonUndefSpecs ++ OptFileUndefSpecs<br>> + OptFileUndefWarnSpecs = OptFileUndefWarnSpecs0<br>> ),<br>> io.environment.get_environment_var_map(EnvVarMap, !IO),<br>> + % XXX DIAG_SPEC we used to include OptFileUndefWarnSpecs in this<br><br>Not sure about that one; are they written out somewhere else?<br><br>...<br><br><br>> diff --git a/compiler/parse_dcg_goal.m b/compiler/parse_dcg_goal.m<br>> index 70e3d7ed4..87e769306 100644<br>> --- a/compiler/parse_dcg_goal.m<br>> +++ b/compiler/parse_dcg_goal.m<br><br>...<br><br><br>> @@ -505,7 +509,7 @@ parse_dcg_goal_some_all(GoalKind, ArgTerms, Context, ContextPieces,<br>> % to warrant a small amount of code target language code duplication.<br>> %<br>> :- pred parse_dcg_goal_conj(dcg_goal_kind, list(term),<br>> - prog_context, cord(format_piece), maybe2(goal, list(warning_spec)),<br>> + prog_context, cord(format_piece), parse_result2(goal),<br>> prog_varset, prog_varset, counter, counter, prog_var, prog_var).<br>> :- mode parse_dcg_goal_conj(in(dcg_goal_kind_conj), in, in, in, out,<br>> in, out, in, out, in, out) is det.<br>> @@ -518,10 +522,13 @@ parse_dcg_goal_conj(GoalKind, ArgTerms, Context, ContextPieces,<br>> string_dcg_goal_kind(Functor, GoalKind),<br>> ( if ArgTerms = [TermA, TermB] then<br>> parse_dcg_goal_conjunction(Functor, TermA, TermB, Context,<br>> - ContextPieces, cord.init, ConjunctsCord, [], Warnings, [], Errors,<br>> - !VarSet, !Counter, !DCGVar),<br>> + ContextPieces, cord.init, ConjunctsCord,<br>> + [], ErrSpecs, [], WarnSpecs, !VarSet, !Counter, !DCGVar),<br>> (<br>> - Errors = [],<br>> + ErrSpecs = [],<br>> + % XXX DIAG_SPEC In the past, we used to get here only if<br>> + % parse_dcg_goal_conjunction returned no diag_specs of<br>> + % *any* severity.<br>> Conjuncts = cord.list(ConjunctsCord),<br><br>The old behaviour seems wrong. parse_goal is called by parse_dcg_goal_conjuction<br>and that can produce warnings.<br><br>...<br><br> <br>> :- pred parse_dcg_goal_semicolon(list(term)::in,<br>> prog_context::in, cord(format_piece)::in,<br>> - maybe2(goal, list(warning_spec))::out,<br>> + parse_result2(goal)::out,<br>> prog_varset::in, prog_varset::out, counter::in, counter::out,<br>> prog_var::in, prog_var::out) is det.<br>> :- pragma inline(pred(parse_dcg_goal_semicolon/10)).<br>> @@ -611,10 +618,13 @@ parse_dcg_goal_semicolon(ArgTerms, Context, ContextPieces,<br>> InitDCGVar = !.DCGVar,<br>> parse_dcg_goal_disjunction(InitDCGVar, ContextPieces,<br>> SubGoalTermA, SubGoalTermB, no, MaybeFirstDiffDCGVar,<br>> - cord.init, DisjunctsDCGVarsCord, [], Warnings, [], ErrorSpecs,<br>> - !VarSet, !Counter),<br>> + cord.init, DisjunctsDCGVarsCord,<br>> + [], ErrSpecs, [], WarnSpecs, !VarSet, !Counter),<br>> (<br>> - ErrorSpecs = [],<br>> + ErrSpecs = [],<br>> + % XXX DIAG_SPEC In the past, we used to get here only if<br>> + % parse_dcg_goal_disjunction returned no diag_specs of<br>> + % *any* severity.<br><br>Ditto for this one.<br><br>...<br><br><br>> diff --git a/compiler/parse_goal.m b/compiler/parse_goal.m<br>> index c40c607a7..5f84f9ddf 100644<br>> --- a/compiler/parse_goal.m<br>> +++ b/compiler/parse_goal.m<br><br>...<br><br><br>> @@ -768,10 +772,13 @@ parse_goal_conj(GoalKind, ArgTerms, Context, ContextPieces,<br>> string_goal_kind(Functor, GoalKind),<br>> ( if ArgTerms = [SubGoalTermA, SubGoalTermB] then<br>> parse_goal_conjunction(Functor, SubGoalTermA, SubGoalTermB,<br>> - ContextPieces, cord.init, ConjunctsCord, [], WarningSpecs,<br>> - [], ErrorSpecs, !VarSet),<br>> + ContextPieces, cord.init, ConjunctsCord,<br>> + [], ErrSpecs, [], WarnSpecs, !VarSet),<br>> (<br>> - ErrorSpecs = [],<br>> + ErrSpecs = [],<br>> + % XXX DIAG_SPEC In the past, we used to get here only if<br>> + % parse_goal_conjunction returned no diag_specs of<br>> + % *any* severity.<br>> Conjuncts = cord.list(ConjunctsCord),<br><br>As in the above DCG cases, the old behaviour seems wrong.<br><br>...<br><br><br>> @@ -852,28 +859,36 @@ parse_goal_semicolon(ArgTerms, Context, ContextPieces, MaybeGoal, !VarSet) :-<br>> parse_goal(ElseGoalTerm, ContextPieces, MaybeElseGoal, !VarSet),<br>> ( if<br>> MaybeCondGoal =<br>> - ok4(Vars, StateVars, CondGoal, CondWarningSpecs),<br>> - MaybeThenGoal = ok2(ThenGoal, ThenWarningSpecs),<br>> - MaybeElseGoal = ok2(ElseGoal, ElseWarningSpecs)<br>> + ok4(Vars, StateVars, CondGoal, CondWarnSpecs),<br>> + MaybeThenGoal = ok2(ThenGoal, ThenWarnSpecs),<br>> + MaybeElseGoal = ok2(ElseGoal, ElseWarnSpecs)<br>> then<br>> Goal = if_then_else_expr(Context, Vars, StateVars,<br>> CondGoal, ThenGoal, ElseGoal),<br>> - WarningSpecs = CondWarningSpecs ++<br>> - ThenWarningSpecs ++ ElseWarningSpecs,<br>> - MaybeGoal = ok2(Goal, WarningSpecs)<br>> + WarnSpecs = CondWarnSpecs ++<br>> + ThenWarnSpecs ++ ElseWarnSpecs,<br>> + MaybeGoal = ok2(Goal, WarnSpecs)<br>> else<br>> - Specs = get_any_errors_warnings4(MaybeCondGoal) ++<br>> - get_any_errors_warnings2(MaybeThenGoal) ++<br>> - get_any_errors_warnings2(MaybeElseGoal),<br>> - det_list_to_one_or_more(Specs, OoMSpecs),<br>> - MaybeGoal = error2(OoMSpecs)<br>> + get_all_errors_warnings4(MaybeCondGoal,<br>> + CondErrSpecs, CondWarnSpecs),<br>> + get_all_errors_warnings2(MaybeThenGoal,<br>> + ThenErrSpecs, ThenWarnSpecs),<br>> + get_all_errors_warnings2(MaybeElseGoal,<br>> + ElseErrSpecs, ElseWarnSpecs),<br>> + ErrSpecs = CondErrSpecs ++ ThenErrSpecs ++ ElseErrSpecs,<br>> + WarnSpecs = CondWarnSpecs ++ ThenWarnSpecs ++ ElseWarnSpecs,<br>> + det_list_to_one_or_more(ErrSpecs, OoMErrSpecs),<br>> + MaybeGoal = error2({OoMErrSpecs, WarnSpecs})<br>> )<br>> else<br>> parse_goal_disjunction(SubGoalTermA, SubGoalTermB, ContextPieces,<br>> - cord.init, DisjunctsCord, [], WarningSpecs, [], ErrorSpecs,<br>> + cord.init, DisjunctsCord, [], ErrSpecs, [], WarnSpecs,<br>> !VarSet),<br>> (<br>> - ErrorSpecs = [],<br>> + ErrSpecs = [],<br>> + % XXX DIAG_SPEC In the past, we used to get here only if<br>> + % parse_goal_disjunction returned no diag_specs of<br>> + % *any* severity.<br>> Disjuncts = cord.list(DisjunctsCord),<br><br><br>Ditto here.<br><br><br>...<br><br>> diff --git a/compiler/parse_item.m b/compiler/parse_item.m<br>> index 18e2ca3da..dc74b1d23 100644<br>> --- a/compiler/parse_item.m<br>> +++ b/compiler/parse_item.m<br><br>...<br><br><br>> @@ -1583,13 +1594,15 @@ read_term_to_iom_result(ModuleName, FileName, ReadTermResult, ReadIOMResult,<br>> ReadTermResult = term(VarSet, Term),<br>> counter.allocate(SeqNum, !SeqNumCounter),<br>> parse_item_or_marker(ModuleName, VarSet, Term, item_seq_num(SeqNum),<br>> - MaybeItemOrMarker),<br>> + MaybeItemOrMarker, [], WarnSpecs),<br>> (<br>> MaybeItemOrMarker = ok1(ItemOrMarker),<br>> + % XXX DIAG_SPEC This ignores WarnSpecs.<br>> ReadIOMResult = read_iom_ok(VarSet, Term, ItemOrMarker)<br>> ;<br>> - MaybeItemOrMarker = error1(Specs),<br>> - ReadIOMResult = read_iom_parse_item_errors(VarSet, Term, Specs)<br>> + MaybeItemOrMarker = error1(OoMErrSpecs),<br>> + ReadIOMResult = read_iom_parse_item_errors(VarSet, Term,<br>> + OoMErrSpecs, WarnSpecs)<br>> )<br>> ).<br>> <br><br>...<br><br>> diff --git a/compiler/read_modules.m b/compiler/read_modules.m<br>> index 24482f774..dc2c19124 100644<br>> --- a/compiler/read_modules.m<br>> +++ b/compiler/read_modules.m<br>> @@ -1487,7 +1487,10 @@ record_and_report_missing_timestamp(Globals, FileName, IOError,<br>> words("Smart recompilation will not work."), nl],<br>> Severity = severity_warning(warn_smart_recompilation),<br>> Spec = no_ctxt_spec($pred, Severity, phase_read_files, Pieces),<br>> - add_nonfatal_error(rme_cannot_find_modify_time, Spec, !Errors)<br>> + % XXX DIAG_SPEC This used to be:<br>> + % add_nonfatal_error(rme_cannot_find_modify_time, Spec, !Errors)<br>> + % but this is a warning, not an error.<br>> + add_warning(Spec, !Errors)<br>> ;<br>> Warn = no<br>> ).<br><br>I don't know about that one. I would leave it marked with an XXX and whoever<br>undertakes the work need to complete smart recompilation can deal with it.<br></div><div><br></div><div>Julien.</div><div><br></div></div></div>