[m-rev.] for review: structured higher order types in type error messages

Peter Wang novalazy at gmail.com
Fri Sep 25 13:15:57 AEST 2020


On Thu, 24 Sep 2020 20:27:00 +1000 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
> diff --git a/compiler/typecheck_errors.m b/compiler/typecheck_errors.m
> index fc2cb2c65..8b063aa6c 100644
> --- a/compiler/typecheck_errors.m
> +++ b/compiler/typecheck_errors.m

> @@ -2529,27 +2554,150 @@ make_list_term([Var | Vars]) =
>      --->    do_not_add_quotes
>      ;       add_quotes.
>  
> -:- func type_to_pieces(maybe_add_quotes, mer_type, tvarset,
> -    external_type_params) = list(format_component).
> +:- func type_to_pieces(maybe_add_quotes, tvarset, inst_varset,
> +    external_type_params, mer_type) = list(format_component).
>  
> -type_to_pieces(MaybeAddQuotes, Type0, TVarSet, ExternalTypeParams) = Pieces :-
> +type_to_pieces(MaybeAddQuotes, TVarSet, InstVarSet, ExternalTypeParams,
> +        Type0) = Pieces :-
>      strip_builtin_qualifiers_from_type(Type0, Type),
> -    unparse_type(Type, Term0),
> -    list.map(term.coerce_var, ExternalTypeParams, ExistQVars),
> -    maybe_add_existential_quantifier(ExistQVars, Term0, Term),
> -    varset.coerce(TVarSet, VarSet),
> -    TermPiece = words(mercury_term_to_string(VarSet, print_name_only, Term)),
>      (
>          MaybeAddQuotes = do_not_add_quotes,
> -        Pieces = [TermPiece]
> +        StartQuotePieces = [],
> +        EndQuotePieces = []
>      ;
>          MaybeAddQuotes = add_quotes,
> -        Pieces = [prefix("`"), TermPiece, suffix("'")]
> +        StartQuotePieces = [error_util.prefix("`")],
> +        EndQuotePieces = [error_util.suffix("'")]
> +    ),
> +    % For most types, we convert the type back to a term, and print that.
> +    % This is done by the final else part of this if-then-else.
> +    % This is ok for most types, which tend to be small.
> +    ( if
> +        % We handle higher order types differently, because when the
> +        % actual and expected types differ in e.g. arity, having each
> +        % argument type on its own line helps readability a *lot*.
> +        Type = higher_order_type(PorF,  ArgTypes, HOInstInfo, Purity,
> +            _LambdaEvalMethod)

Double space there.

> +    then
> +        ( Purity = purity_pure,     PurityPieces = []
> +        ; Purity = purity_semipure, PurityPieces = [words("semipure")]
> +        ; Purity = purity_impure,   PurityPieces = [words("impure")]
> +        ),
> +        ( PorF = pf_predicate,      PorFPieces = [words("pred")]
> +        ; PorF = pf_function,       PorFPieces = [words("func")]
> +        ),
> +        (
> +            HOInstInfo = none_or_default_func,
> +            ArgPieces = list.map(
> +                type_to_pieces(do_not_add_quotes, TVarSet, InstVarSet,
> +                    ExternalTypeParams),
> +                ArgTypes),
> +            FuncResultPrefixPieces = [],
> +            FuncResultSuffixPieces = [],
> +            DetismPieces = [],
> +            PorFMismatchPieces = [],
> +            ArityMismatchPieces = []
> +        ;
> +            HOInstInfo = higher_order(PredInstInfo),
> +            PorFStr = pred_or_func_to_full_str(PorF),
> +            PredInstInfo = pred_inst_info(HOPorF, ArgModes, _ArgRegs, Detism),
> +            ( if PorF = HOPorF then
> +                PorFMismatchPieces = []
> +            else
> +                HOPorFStr = pred_or_func_to_full_str(HOPorF),
> +                PorFMismatchPieces = [nl,
> +                    words("The type says this is a"),
> +                    words(PorFStr), suffix(","),
> +                    words("but its mode says it is a"),
> +                    words(HOPorFStr), suffix(".")]
> +            ),
> +            list.length(ArgTypes, NumArgTypes),
> +            list.length(ArgModes, NumArgModes),
> +            ( if NumArgTypes = NumArgModes then
> +                assoc_list.from_corresponding_lists(ArgTypes, ArgModes,
> +                    ArgTypesModes),
> +                % If this higher order type is a function, then the type::mode
> +                % for the function result must be wrapped in parentheses.
> +                FuncResultPrefixPieces = [error_util.prefix("(")],
> +                FuncResultSuffixPieces = [error_util.suffix("(")],

Fix the close parenthesis.

> @@ -2721,6 +2869,21 @@ arg_type_assign_set_msg_to_verbose_pieces(Info, ArgTypeAssignSet, VarSet,
>          VerboseComponents = [verbose_only(verbose_always, VerbosePieces)]
>      ).
>  
> +%-----------------------------------------------------------------------------%
> +
> +:- pred get_inst_varset(type_error_clause_context::in, inst_varset::out)
> +    is det.
> +
> +get_inst_varset(ClauseContext, InstVarSet) :-
> +    % XXX Typechecking works on pred_infos, which do NOT have an inst_varset.
> +    % I (zs) don't know where the inst variables in any ho_inst_infos
> +    % in higher-order types come from, but I am *guessing* that it is
> +    % from the varset of the clause itself. I am not even sure whether
> +    % this matters, since I don't know whether ho_inst_infos can ever
> +    % be filled in before the end of typechecking.
> +    ProgVarSet = ClauseContext ^ tecc_varset,
> +    varset.coerce(ProgVarSet, InstVarSet).

I don't know; would need to investigate.

The rest looks fine.

Peter


More information about the reviews mailing list