remove synthetic default expression for variables

Now that variable evaluation checks for a nil expression the graph
transformer does not need to generate a synthetic expression for
variable defaults. This means that all default handling is now located
in one place, and we are not surprised by a configuration expression
showing up which doesn't actually exist in the configuration.

Rename nodeModuleVariable.evalModuleCallArgument to evalModuleVariable.
This method is no longer handling only the module call argument, it is
also dealing with the variable declaration defaults and validation
statements.

Add an additional tests for validation with a non-nullable variable.
This commit is contained in:
James Bardin 2022-01-10 16:14:30 -05:00
parent dabd7567af
commit 684ed7505d
3 changed files with 37 additions and 12 deletions

View File

@ -2062,3 +2062,36 @@ output "out" {
t.Fatal(diags.ErrWithWarnings())
}
}
func TestContext2Validate_nonNullableVariableDefaultValidation(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
module "first" {
source = "./mod"
input = null
}
`,
"mod/main.tf": `
variable "input" {
type = string
default = "default"
nullable = false
// Validation expressions should receive the default with nullable=false and
// a null input.
validation {
condition = var.input != null
error_message = "Input cannot be null!"
}
}
`,
})
ctx := testContext2(t, &ContextOpts{})
diags := ctx.Validate(m)
if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}
}

View File

@ -149,10 +149,10 @@ func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) (diags t
switch op {
case walkValidate:
val, err = n.evalModuleCallArgument(ctx, true)
val, err = n.evalModuleVariable(ctx, true)
diags = diags.Append(err)
default:
val, err = n.evalModuleCallArgument(ctx, false)
val, err = n.evalModuleVariable(ctx, false)
diags = diags.Append(err)
}
if diags.HasErrors() {
@ -178,7 +178,7 @@ func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNod
}
}
// evalModuleCallArgument produces the value for a particular variable as will
// evalModuleVariable produces the value for a particular variable as will
// be used by a child module instance.
//
// The result is written into a map, with its key set to the local name of the
@ -190,7 +190,7 @@ func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNod
// validateOnly indicates that this evaluation is only for config
// validation, and we will not have any expansion module instance
// repetition data.
func (n *nodeModuleVariable) evalModuleCallArgument(ctx EvalContext, validateOnly bool) (cty.Value, error) {
func (n *nodeModuleVariable) evalModuleVariable(ctx EvalContext, validateOnly bool) (cty.Value, error) {
var diags tfdiags.Diagnostics
var givenVal cty.Value
var errSourceRange tfdiags.SourceRange

View File

@ -3,7 +3,6 @@ package terraform
import (
"fmt"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/zclconf/go-cty/cty"
@ -94,13 +93,6 @@ func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs
var expr hcl.Expression
if attr := content.Attributes[v.Name]; attr != nil {
expr = attr.Expr
} else {
// No expression provided for this variable, so we'll make a
// synthetic one using the variable's default value.
expr = &hclsyntax.LiteralValueExpr{
Val: v.Default,
SrcRange: v.DeclRange, // This is not exact, but close enough
}
}
// Add a plannable node, as the variable may expand