hcl: Annotate diagnostics with expression EvalContext
When we're evaluating expressions, we may end up evaluating the same source-level expression a number of times in different contexts, such as in a 'for' expression, where each one may produce a different set of diagnostic messages. Now we'll attach the EvalContext to each expression diagnostic so that a diagnostic renderer can potentially show additional information to help distinguish the different iterations in rendered diagnostics.
This commit is contained in:
parent
41cff854d8
commit
93562f805f
@ -43,19 +43,21 @@ func (b *expandBody) decodeSpec(blockS *hcl.BlockHeaderSchema, rawSpec *hcl.Bloc
|
|||||||
|
|
||||||
if !eachVal.CanIterateElements() {
|
if !eachVal.CanIterateElements() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid dynamic for_each value",
|
Summary: "Invalid dynamic for_each value",
|
||||||
Detail: fmt.Sprintf("Cannot use a value of type %s in for_each. An iterable collection is required.", eachVal.Type()),
|
Detail: fmt.Sprintf("Cannot use a value of type %s in for_each. An iterable collection is required.", eachVal.Type()),
|
||||||
Subject: eachAttr.Expr.Range().Ptr(),
|
Subject: eachAttr.Expr.Range().Ptr(),
|
||||||
|
EvalContext: b.forEachCtx,
|
||||||
})
|
})
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
if eachVal.IsNull() {
|
if eachVal.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid dynamic for_each value",
|
Summary: "Invalid dynamic for_each value",
|
||||||
Detail: "Cannot use a null value in for_each.",
|
Detail: "Cannot use a null value in for_each.",
|
||||||
Subject: eachAttr.Expr.Range().Ptr(),
|
Subject: eachAttr.Expr.Range().Ptr(),
|
||||||
|
EvalContext: b.forEachCtx,
|
||||||
})
|
})
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
@ -159,28 +161,31 @@ func (s *expandSpec) newBlock(i *iteration, ctx *hcl.EvalContext) (*hcl.Block, h
|
|||||||
labelVal, convErr = convert.Convert(labelVal, cty.String)
|
labelVal, convErr = convert.Convert(labelVal, cty.String)
|
||||||
if convErr != nil {
|
if convErr != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid dynamic block label",
|
Summary: "Invalid dynamic block label",
|
||||||
Detail: fmt.Sprintf("Cannot use this value as a dynamic block label: %s.", convErr),
|
Detail: fmt.Sprintf("Cannot use this value as a dynamic block label: %s.", convErr),
|
||||||
Subject: labelExpr.Range().Ptr(),
|
Subject: labelExpr.Range().Ptr(),
|
||||||
|
EvalContext: lCtx,
|
||||||
})
|
})
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
if labelVal.IsNull() {
|
if labelVal.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid dynamic block label",
|
Summary: "Invalid dynamic block label",
|
||||||
Detail: "Cannot use a null value as a dynamic block label.",
|
Detail: "Cannot use a null value as a dynamic block label.",
|
||||||
Subject: labelExpr.Range().Ptr(),
|
Subject: labelExpr.Range().Ptr(),
|
||||||
|
EvalContext: lCtx,
|
||||||
})
|
})
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
if !labelVal.IsKnown() {
|
if !labelVal.IsKnown() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid dynamic block label",
|
Summary: "Invalid dynamic block label",
|
||||||
Detail: "This value is not yet known. Dynamic block labels must be immediately-known values.",
|
Detail: "This value is not yet known. Dynamic block labels must be immediately-known values.",
|
||||||
Subject: labelExpr.Range().Ptr(),
|
Subject: labelExpr.Range().Ptr(),
|
||||||
|
EvalContext: lCtx,
|
||||||
})
|
})
|
||||||
return nil, diags
|
return nil, diags
|
||||||
}
|
}
|
||||||
|
@ -26,14 +26,43 @@ const (
|
|||||||
type Diagnostic struct {
|
type Diagnostic struct {
|
||||||
Severity DiagnosticSeverity
|
Severity DiagnosticSeverity
|
||||||
|
|
||||||
// Summary and detail contain the English-language description of the
|
// Summary and Detail contain the English-language description of the
|
||||||
// problem. Summary is a terse description of the general problem and
|
// problem. Summary is a terse description of the general problem and
|
||||||
// detail is a more elaborate, often-multi-sentence description of
|
// detail is a more elaborate, often-multi-sentence description of
|
||||||
// the probem and what might be done to solve it.
|
// the probem and what might be done to solve it.
|
||||||
Summary string
|
Summary string
|
||||||
Detail string
|
Detail string
|
||||||
|
|
||||||
|
// Subject and Context are both source ranges relating to the diagnostic.
|
||||||
|
//
|
||||||
|
// Subject is a tight range referring to exactly the construct that
|
||||||
|
// is problematic, while Context is an optional broader range (which should
|
||||||
|
// fully contain Subject) that ought to be shown around Subject when
|
||||||
|
// generating isolated source-code snippets in diagnostic messages.
|
||||||
|
// If Context is nil, the Subject is also the Context.
|
||||||
|
//
|
||||||
|
// Some diagnostics have no source ranges at all. If Context is set then
|
||||||
|
// Subject should always also be set.
|
||||||
Subject *Range
|
Subject *Range
|
||||||
Context *Range
|
Context *Range
|
||||||
|
|
||||||
|
// For diagnostics that occur when evaluating an expression, EvalContext
|
||||||
|
// may point to the EvalContext that was active when evaluating that
|
||||||
|
// expression, which may allow for the inclusion of additional useful
|
||||||
|
// information when rendering a diagnostic message to the user.
|
||||||
|
//
|
||||||
|
// It is not always possible to select a single EvalContext for a
|
||||||
|
// diagnostic, and so in some cases this field may be nil even when an
|
||||||
|
// expression causes a problem. Therefore it is not valid to use the
|
||||||
|
// nil-ness of this field to definitively decide whether a diagnostic
|
||||||
|
// relates to an expression.
|
||||||
|
//
|
||||||
|
// EvalContexts form a tree, so the given EvalContext may refer to a parent
|
||||||
|
// which in turn refers to another parent, etc. For a full picture of all
|
||||||
|
// of the active variables and functions the caller must walk up this
|
||||||
|
// chain, preferring definitions that are "closer" to the expression in
|
||||||
|
// case of colliding names.
|
||||||
|
EvalContext *EvalContext
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnostics is a list of Diagnostic instances.
|
// Diagnostics is a list of Diagnostic instances.
|
||||||
|
22
hcl/hclsyntax/diagnostics.go
Normal file
22
hcl/hclsyntax/diagnostics.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package hclsyntax
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/hcl2/hcl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setDiagEvalContext is an internal helper that will impose a particular
|
||||||
|
// EvalContext on a set of diagnostics in-place, for any diagnostic that
|
||||||
|
// does not already have an EvalContext set.
|
||||||
|
//
|
||||||
|
// We generally expect diagnostics to be immutable, but this is safe to use
|
||||||
|
// on any Diagnostics where none of the contained Diagnostic objects have yet
|
||||||
|
// been seen by a caller. Its purpose is to apply additional context to a
|
||||||
|
// set of diagnostics produced by a "deeper" component as the stack unwinds
|
||||||
|
// during expression evaluation.
|
||||||
|
func setDiagEvalContext(diags hcl.Diagnostics, ctx *hcl.EvalContext) {
|
||||||
|
for _, diag := range diags {
|
||||||
|
if diag.EvalContext == nil {
|
||||||
|
diag.EvalContext = ctx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -105,7 +105,9 @@ func (e *ScopeTraversalExpr) walkChildNodes(w internalWalkFunc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *ScopeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
func (e *ScopeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||||
return e.Traversal.TraverseAbs(ctx)
|
val, diags := e.Traversal.TraverseAbs(ctx)
|
||||||
|
setDiagEvalContext(diags, ctx)
|
||||||
|
return val, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ScopeTraversalExpr) Range() hcl.Range {
|
func (e *ScopeTraversalExpr) Range() hcl.Range {
|
||||||
@ -136,6 +138,7 @@ func (e *RelativeTraversalExpr) walkChildNodes(w internalWalkFunc) {
|
|||||||
func (e *RelativeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
func (e *RelativeTraversalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
||||||
src, diags := e.Source.Value(ctx)
|
src, diags := e.Source.Value(ctx)
|
||||||
ret, travDiags := e.Traversal.TraverseRel(src)
|
ret, travDiags := e.Traversal.TraverseRel(src)
|
||||||
|
setDiagEvalContext(travDiags, ctx)
|
||||||
diags = append(diags, travDiags...)
|
diags = append(diags, travDiags...)
|
||||||
return ret, diags
|
return ret, diags
|
||||||
}
|
}
|
||||||
@ -207,10 +210,11 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
if !hasNonNilMap {
|
if !hasNonNilMap {
|
||||||
return cty.DynamicVal, hcl.Diagnostics{
|
return cty.DynamicVal, hcl.Diagnostics{
|
||||||
{
|
{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Function calls not allowed",
|
Summary: "Function calls not allowed",
|
||||||
Detail: "Functions may not be called here.",
|
Detail: "Functions may not be called here.",
|
||||||
Subject: e.Range().Ptr(),
|
Subject: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,11 +230,12 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
|
|
||||||
return cty.DynamicVal, hcl.Diagnostics{
|
return cty.DynamicVal, hcl.Diagnostics{
|
||||||
{
|
{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Call to unknown function",
|
Summary: "Call to unknown function",
|
||||||
Detail: fmt.Sprintf("There is no function named %q.%s", e.Name, suggestion),
|
Detail: fmt.Sprintf("There is no function named %q.%s", e.Name, suggestion),
|
||||||
Subject: &e.NameRange,
|
Subject: &e.NameRange,
|
||||||
Context: e.Range().Ptr(),
|
Context: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,11 +260,12 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
case expandVal.Type().IsTupleType() || expandVal.Type().IsListType() || expandVal.Type().IsSetType():
|
case expandVal.Type().IsTupleType() || expandVal.Type().IsListType() || expandVal.Type().IsSetType():
|
||||||
if expandVal.IsNull() {
|
if expandVal.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid expanding argument value",
|
Summary: "Invalid expanding argument value",
|
||||||
Detail: "The expanding argument (indicated by ...) must not be null.",
|
Detail: "The expanding argument (indicated by ...) must not be null.",
|
||||||
Context: expandExpr.Range().Ptr(),
|
Context: expandExpr.Range().Ptr(),
|
||||||
Subject: e.Range().Ptr(),
|
Subject: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
@ -280,11 +286,12 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
args = newArgs
|
args = newArgs
|
||||||
default:
|
default:
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid expanding argument value",
|
Summary: "Invalid expanding argument value",
|
||||||
Detail: "The expanding argument (indicated by ...) must be of a tuple, list, or set type.",
|
Detail: "The expanding argument (indicated by ...) must be of a tuple, list, or set type.",
|
||||||
Context: expandExpr.Range().Ptr(),
|
Context: expandExpr.Range().Ptr(),
|
||||||
Subject: e.Range().Ptr(),
|
Subject: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
@ -304,8 +311,9 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
"Function %q expects%s %d argument(s). Missing value for %q.",
|
"Function %q expects%s %d argument(s). Missing value for %q.",
|
||||||
e.Name, qual, len(params), missing.Name,
|
e.Name, qual, len(params), missing.Name,
|
||||||
),
|
),
|
||||||
Subject: &e.CloseParenRange,
|
Subject: &e.CloseParenRange,
|
||||||
Context: e.Range().Ptr(),
|
Context: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,8 +327,9 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
"Function %q expects only %d argument(s).",
|
"Function %q expects only %d argument(s).",
|
||||||
e.Name, len(params),
|
e.Name, len(params),
|
||||||
),
|
),
|
||||||
Subject: args[len(params)].StartRange().Ptr(),
|
Subject: args[len(params)].StartRange().Ptr(),
|
||||||
Context: e.Range().Ptr(),
|
Context: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,8 +359,9 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
"Invalid value for %q parameter: %s.",
|
"Invalid value for %q parameter: %s.",
|
||||||
param.Name, err,
|
param.Name, err,
|
||||||
),
|
),
|
||||||
Subject: argExpr.StartRange().Ptr(),
|
Subject: argExpr.StartRange().Ptr(),
|
||||||
Context: e.Range().Ptr(),
|
Context: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,8 +397,9 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
"Invalid value for %q parameter: %s.",
|
"Invalid value for %q parameter: %s.",
|
||||||
param.Name, err,
|
param.Name, err,
|
||||||
),
|
),
|
||||||
Subject: argExpr.StartRange().Ptr(),
|
Subject: argExpr.StartRange().Ptr(),
|
||||||
Context: e.Range().Ptr(),
|
Context: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -399,8 +410,9 @@ func (e *FunctionCallExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
"Call to function %q failed: %s.",
|
"Call to function %q failed: %s.",
|
||||||
e.Name, err,
|
e.Name, err,
|
||||||
),
|
),
|
||||||
Subject: e.StartRange().Ptr(),
|
Subject: e.StartRange().Ptr(),
|
||||||
Context: e.Range().Ptr(),
|
Context: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,8 +479,9 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
|
|||||||
"The true and false result expressions must have consistent types. The given expressions are %s and %s, respectively.",
|
"The true and false result expressions must have consistent types. The given expressions are %s and %s, respectively.",
|
||||||
trueResult.Type(), falseResult.Type(),
|
trueResult.Type(), falseResult.Type(),
|
||||||
),
|
),
|
||||||
Subject: hcl.RangeBetween(e.TrueResult.Range(), e.FalseResult.Range()).Ptr(),
|
Subject: hcl.RangeBetween(e.TrueResult.Range(), e.FalseResult.Range()).Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,11 +490,12 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
|
|||||||
diags = append(diags, condDiags...)
|
diags = append(diags, condDiags...)
|
||||||
if condResult.IsNull() {
|
if condResult.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Null condition",
|
Summary: "Null condition",
|
||||||
Detail: "The condition value is null. Conditions must either be true or false.",
|
Detail: "The condition value is null. Conditions must either be true or false.",
|
||||||
Subject: e.Condition.Range().Ptr(),
|
Subject: e.Condition.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.UnknownVal(resultType), diags
|
return cty.UnknownVal(resultType), diags
|
||||||
}
|
}
|
||||||
@ -491,11 +505,12 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
|
|||||||
condResult, err := convert.Convert(condResult, cty.Bool)
|
condResult, err := convert.Convert(condResult, cty.Bool)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Incorrect condition type",
|
Summary: "Incorrect condition type",
|
||||||
Detail: fmt.Sprintf("The condition expression must be of type bool."),
|
Detail: fmt.Sprintf("The condition expression must be of type bool."),
|
||||||
Subject: e.Condition.Range().Ptr(),
|
Subject: e.Condition.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.UnknownVal(resultType), diags
|
return cty.UnknownVal(resultType), diags
|
||||||
}
|
}
|
||||||
@ -514,8 +529,9 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
|
|||||||
"The true result value has the wrong type: %s.",
|
"The true result value has the wrong type: %s.",
|
||||||
err.Error(),
|
err.Error(),
|
||||||
),
|
),
|
||||||
Subject: e.TrueResult.Range().Ptr(),
|
Subject: e.TrueResult.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
trueResult = cty.UnknownVal(resultType)
|
trueResult = cty.UnknownVal(resultType)
|
||||||
}
|
}
|
||||||
@ -535,8 +551,9 @@ func (e *ConditionalExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostic
|
|||||||
"The false result value has the wrong type: %s.",
|
"The false result value has the wrong type: %s.",
|
||||||
err.Error(),
|
err.Error(),
|
||||||
),
|
),
|
||||||
Subject: e.TrueResult.Range().Ptr(),
|
Subject: e.TrueResult.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
falseResult = cty.UnknownVal(resultType)
|
falseResult = cty.UnknownVal(resultType)
|
||||||
}
|
}
|
||||||
@ -676,10 +693,11 @@ func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics
|
|||||||
|
|
||||||
if key.IsNull() {
|
if key.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Null value as key",
|
Summary: "Null value as key",
|
||||||
Detail: "Can't use a null value as a key.",
|
Detail: "Can't use a null value as a key.",
|
||||||
Subject: item.ValueExpr.Range().Ptr(),
|
Subject: item.ValueExpr.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
known = false
|
known = false
|
||||||
continue
|
continue
|
||||||
@ -689,10 +707,11 @@ func (e *ObjectConsExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics
|
|||||||
key, err = convert.Convert(key, cty.String)
|
key, err = convert.Convert(key, cty.String)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Incorrect key type",
|
Summary: "Incorrect key type",
|
||||||
Detail: fmt.Sprintf("Can't use this value as a key: %s.", err.Error()),
|
Detail: fmt.Sprintf("Can't use this value as a key: %s.", err.Error()),
|
||||||
Subject: item.ValueExpr.Range().Ptr(),
|
Subject: item.ValueExpr.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
known = false
|
known = false
|
||||||
continue
|
continue
|
||||||
@ -819,11 +838,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
|
|
||||||
if collVal.IsNull() {
|
if collVal.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Iteration over null value",
|
Summary: "Iteration over null value",
|
||||||
Detail: "A null value cannot be used as the collection in a 'for' expression.",
|
Detail: "A null value cannot be used as the collection in a 'for' expression.",
|
||||||
Subject: e.CollExpr.Range().Ptr(),
|
Subject: e.CollExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
@ -838,8 +858,9 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
"A value of type %s cannot be used as the collection in a 'for' expression.",
|
"A value of type %s cannot be used as the collection in a 'for' expression.",
|
||||||
collVal.Type().FriendlyName(),
|
collVal.Type().FriendlyName(),
|
||||||
),
|
),
|
||||||
Subject: e.CollExpr.Range().Ptr(),
|
Subject: e.CollExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
@ -864,22 +885,24 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
diags = append(diags, condDiags...)
|
diags = append(diags, condDiags...)
|
||||||
if result.IsNull() {
|
if result.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Condition is null",
|
Summary: "Condition is null",
|
||||||
Detail: "The value of the 'if' clause must not be null.",
|
Detail: "The value of the 'if' clause must not be null.",
|
||||||
Subject: e.CondExpr.Range().Ptr(),
|
Subject: e.CondExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
_, err := convert.Convert(result, cty.Bool)
|
_, err := convert.Convert(result, cty.Bool)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid 'for' condition",
|
Summary: "Invalid 'for' condition",
|
||||||
Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
|
Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
|
||||||
Subject: e.CondExpr.Range().Ptr(),
|
Subject: e.CondExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
@ -914,11 +937,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
if includeRaw.IsNull() {
|
if includeRaw.IsNull() {
|
||||||
if known {
|
if known {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Condition is null",
|
Summary: "Invalid 'for' condition",
|
||||||
Detail: "The value of the 'if' clause must not be null.",
|
Detail: "The value of the 'if' clause must not be null.",
|
||||||
Subject: e.CondExpr.Range().Ptr(),
|
Subject: e.CondExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
known = false
|
known = false
|
||||||
@ -928,11 +952,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if known {
|
if known {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid 'for' condition",
|
Summary: "Invalid 'for' condition",
|
||||||
Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
|
Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
|
||||||
Subject: e.CondExpr.Range().Ptr(),
|
Subject: e.CondExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
known = false
|
known = false
|
||||||
@ -954,11 +979,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
if keyRaw.IsNull() {
|
if keyRaw.IsNull() {
|
||||||
if known {
|
if known {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid object key",
|
Summary: "Invalid object key",
|
||||||
Detail: "Key expression in 'for' expression must not produce a null value.",
|
Detail: "Key expression in 'for' expression must not produce a null value.",
|
||||||
Subject: e.KeyExpr.Range().Ptr(),
|
Subject: e.KeyExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
known = false
|
known = false
|
||||||
@ -973,11 +999,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if known {
|
if known {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid object key",
|
Summary: "Invalid object key",
|
||||||
Detail: fmt.Sprintf("The key expression produced an invalid result: %s.", err.Error()),
|
Detail: fmt.Sprintf("The key expression produced an invalid result: %s.", err.Error()),
|
||||||
Subject: e.KeyExpr.Range().Ptr(),
|
Subject: e.KeyExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
known = false
|
known = false
|
||||||
@ -997,11 +1024,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Duplicate object key",
|
Summary: "Duplicate object key",
|
||||||
Detail: fmt.Sprintf(
|
Detail: fmt.Sprintf(
|
||||||
"Two different items produced the key %q in this for expression. If duplicates are expected, use the ellipsis (...) after the value expression to enable grouping by key.",
|
"Two different items produced the key %q in this 'for' expression. If duplicates are expected, use the ellipsis (...) after the value expression to enable grouping by key.",
|
||||||
k,
|
k,
|
||||||
),
|
),
|
||||||
Subject: e.KeyExpr.Range().Ptr(),
|
Subject: e.KeyExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
vals[key.AsString()] = val
|
vals[key.AsString()] = val
|
||||||
@ -1042,11 +1070,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
if includeRaw.IsNull() {
|
if includeRaw.IsNull() {
|
||||||
if known {
|
if known {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Condition is null",
|
Summary: "Invalid 'for' condition",
|
||||||
Detail: "The value of the 'if' clause must not be null.",
|
Detail: "The value of the 'if' clause must not be null.",
|
||||||
Subject: e.CondExpr.Range().Ptr(),
|
Subject: e.CondExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
known = false
|
known = false
|
||||||
@ -1064,11 +1093,12 @@ func (e *ForExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if known {
|
if known {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid 'for' condition",
|
Summary: "Invalid 'for' condition",
|
||||||
Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
|
Detail: fmt.Sprintf("The 'if' clause value is invalid: %s.", err.Error()),
|
||||||
Subject: e.CondExpr.Range().Ptr(),
|
Subject: e.CondExpr.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
known = false
|
known = false
|
||||||
@ -1154,11 +1184,12 @@ func (e *SplatExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
|
|
||||||
if sourceVal.IsNull() {
|
if sourceVal.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Splat of null value",
|
Summary: "Splat of null value",
|
||||||
Detail: "Splat expressions (with the * symbol) cannot be applied to null values.",
|
Detail: "Splat expressions (with the * symbol) cannot be applied to null values.",
|
||||||
Subject: e.Source.Range().Ptr(),
|
Subject: e.Source.Range().Ptr(),
|
||||||
Context: hcl.RangeBetween(e.Source.Range(), e.MarkerRange).Ptr(),
|
Context: hcl.RangeBetween(e.Source.Range(), e.MarkerRange).Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.DynamicVal, diags
|
return cty.DynamicVal, diags
|
||||||
}
|
}
|
||||||
|
@ -149,21 +149,23 @@ func (e *BinaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
|
|||||||
lhsVal, err := convert.Convert(givenLHSVal, lhsParam.Type)
|
lhsVal, err := convert.Convert(givenLHSVal, lhsParam.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid operand",
|
Summary: "Invalid operand",
|
||||||
Detail: fmt.Sprintf("Unsuitable value for left operand: %s.", err),
|
Detail: fmt.Sprintf("Unsuitable value for left operand: %s.", err),
|
||||||
Subject: e.LHS.Range().Ptr(),
|
Subject: e.LHS.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
rhsVal, err := convert.Convert(givenRHSVal, rhsParam.Type)
|
rhsVal, err := convert.Convert(givenRHSVal, rhsParam.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid operand",
|
Summary: "Invalid operand",
|
||||||
Detail: fmt.Sprintf("Unsuitable value for right operand: %s.", err),
|
Detail: fmt.Sprintf("Unsuitable value for right operand: %s.", err),
|
||||||
Subject: e.RHS.Range().Ptr(),
|
Subject: e.RHS.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,10 +180,11 @@ func (e *BinaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
// FIXME: This diagnostic is useless.
|
// FIXME: This diagnostic is useless.
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Operation failed",
|
Summary: "Operation failed",
|
||||||
Detail: fmt.Sprintf("Error during operation: %s.", err),
|
Detail: fmt.Sprintf("Error during operation: %s.", err),
|
||||||
Subject: &e.SrcRange,
|
Subject: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.UnknownVal(e.Op.Type), diags
|
return cty.UnknownVal(e.Op.Type), diags
|
||||||
}
|
}
|
||||||
@ -219,11 +222,12 @@ func (e *UnaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
val, err := convert.Convert(givenVal, param.Type)
|
val, err := convert.Convert(givenVal, param.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid operand",
|
Summary: "Invalid operand",
|
||||||
Detail: fmt.Sprintf("Unsuitable value for unary operand: %s.", err),
|
Detail: fmt.Sprintf("Unsuitable value for unary operand: %s.", err),
|
||||||
Subject: e.Val.Range().Ptr(),
|
Subject: e.Val.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,10 +242,11 @@ func (e *UnaryOpExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
// FIXME: This diagnostic is useless.
|
// FIXME: This diagnostic is useless.
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Operation failed",
|
Summary: "Operation failed",
|
||||||
Detail: fmt.Sprintf("Error during operation: %s.", err),
|
Detail: fmt.Sprintf("Error during operation: %s.", err),
|
||||||
Subject: &e.SrcRange,
|
Subject: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
return cty.UnknownVal(e.Op.Type), diags
|
return cty.UnknownVal(e.Op.Type), diags
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,9 @@ func (e *TemplateExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
|
|||||||
Detail: fmt.Sprintf(
|
Detail: fmt.Sprintf(
|
||||||
"The expression result is null. Cannot include a null value in a string template.",
|
"The expression result is null. Cannot include a null value in a string template.",
|
||||||
),
|
),
|
||||||
Subject: part.Range().Ptr(),
|
Subject: part.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -61,8 +62,9 @@ func (e *TemplateExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics)
|
|||||||
"Cannot include the given value in a string template: %s.",
|
"Cannot include the given value in a string template: %s.",
|
||||||
err.Error(),
|
err.Error(),
|
||||||
),
|
),
|
||||||
Subject: part.Range().Ptr(),
|
Subject: part.Range().Ptr(),
|
||||||
Context: &e.SrcRange,
|
Context: &e.SrcRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -127,7 +129,8 @@ func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
Detail: fmt.Sprintf(
|
Detail: fmt.Sprintf(
|
||||||
"An iteration result is null. Cannot include a null value in a string template.",
|
"An iteration result is null. Cannot include a null value in a string template.",
|
||||||
),
|
),
|
||||||
Subject: e.Range().Ptr(),
|
Subject: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -143,7 +146,8 @@ func (e *TemplateJoinExpr) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnosti
|
|||||||
"Cannot include one of the interpolation results into the string template: %s.",
|
"Cannot include one of the interpolation results into the string template: %s.",
|
||||||
err.Error(),
|
err.Error(),
|
||||||
),
|
),
|
||||||
Subject: e.Range().Ptr(),
|
Subject: e.Range().Ptr(),
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -440,19 +440,21 @@ func (e *expression) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
name, err = convert.Convert(name, cty.String)
|
name, err = convert.Convert(name, cty.String)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid object key expression",
|
Summary: "Invalid object key expression",
|
||||||
Detail: fmt.Sprintf("Cannot use this expression as an object key: %s.", err),
|
Detail: fmt.Sprintf("Cannot use this expression as an object key: %s.", err),
|
||||||
Subject: &jsonAttr.NameRange,
|
Subject: &jsonAttr.NameRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if name.IsNull() {
|
if name.IsNull() {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid object key expression",
|
Summary: "Invalid object key expression",
|
||||||
Detail: "Cannot use null value as an object key.",
|
Detail: "Cannot use null value as an object key.",
|
||||||
Subject: &jsonAttr.NameRange,
|
Subject: &jsonAttr.NameRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -471,10 +473,11 @@ func (e *expression) Value(ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
|
|||||||
nameStr := name.AsString()
|
nameStr := name.AsString()
|
||||||
if _, defined := attrs[nameStr]; defined {
|
if _, defined := attrs[nameStr]; defined {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Duplicate object attribute",
|
Summary: "Duplicate object attribute",
|
||||||
Detail: fmt.Sprintf("An attribute named %q was already defined at %s.", nameStr, attrRanges[nameStr]),
|
Detail: fmt.Sprintf("An attribute named %q was already defined at %s.", nameStr, attrRanges[nameStr]),
|
||||||
Subject: &jsonAttr.NameRange,
|
Subject: &jsonAttr.NameRange,
|
||||||
|
EvalContext: ctx,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user