Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hcl: Allow individual diagnostics to carry extra information #539

Merged
merged 1 commit into from Jun 22, 2022

Commits on Jun 21, 2022

  1. hcl: Allow individual diagnostics to carry extra information

    The primary goal of the diagnostics design in HCL is to return
    high-quality diagnostics messages primarily for human consumption, and so
    their regular structure is only machine-processable in a general sense
    where we treat all diagnostics as subject to the same processing.
    
    A few times now we've ended up wanting to carry some additional optional
    contextual information along with the diagnostic, for example so that a
    more advanced diagnostics renderer might optionally annotate a diagnostic
    with extra notes to help the reader debug.
    
    We got pretty far with our previous extension of hcl.Diagnostic to include
    the Expression and EvalContext fields, which allow an advanced diagnostic
    renderer to offer hints about what values contributed to the expression
    that failed, but some context is even more specific than that, or is
    defined by the application itself and therefore not appropriate to model
    directly here in HCL.
    
    As a pragmatic compromise then, here we introduce one more field Extra
    to hcl.Diagnostic, which comes with a documented convention of placing
    into it situation-specific values that implement particular interfaces,
    and therefore a diagnostics renderer or other consumer can potentially
    "sniff" this field for particular interfaces it knows about and treat them
    in a special way if present.
    
    Since there is only one field here that might end up being asked to
    capture multiple extra values as the call stack unwinds, there is also a
    simple predefined protocol for "unwrapping" extra values in order to find
    nested implementations within.
    
    
    For callers that are prepared to require Go 1.18, the helper function
    hcl.DiagnosticExtra provides a type-assertion-like mechanism for sniffing
    for a particular interface type while automatically respecting the nesting
    protocol. For the moment that function lives behind a build constraint
    so that callers which are not yet ready to use Go 1.18 can continue to
    use other parts of HCL, and can implement a non-generic equivalent of
    this function within their own codebase if absolutely necessary.
    
    As an initial example to demonstrate the idea I've also implemented some
    extra information for error diagnostics returned from FunctionCallExpr,
    which gives the name of the function being called and, if the diagnostic
    is describing an error returned by the function itself, a direct reference
    to the raw error value returned from the function call. I anticipate a
    diagnostic renderer sniffing for hclsyntax.FunctionCallDiagExtra to see
    if a particular diagnostic is related to a function call, and if so to
    include additional context about the signature of that function in the
    diagnostic messages (by correlating with the function in the EvalContext
    functions table). For example:
        While calling: join(separator, list)
    
    An example application-specific "extra value" could be for Terraform to
    annotate diagnostics that relate to situations where an unknown value is
    invalid, or where a "sensitive" value (a Terraform-specific value mark) is
    invalid, so that the diagnostic renderer can avoid distracting users with
    "red herring" commentary about unknown or sensitive values unless they
    seem likely to be relevant to the error being printed.
    apparentlymart committed Jun 21, 2022
    Copy the full SHA
    6513c01 View commit details
    Browse the repository at this point in the history