diff --git a/internal/terraform/context_eval.go b/internal/terraform/context_eval.go index e0ca20ad320d..891824ea42d9 100644 --- a/internal/terraform/context_eval.go +++ b/internal/terraform/context_eval.go @@ -116,6 +116,6 @@ func evalScopeFromGraphWalk(walker *ContextGraphWalker, moduleAddr addrs.ModuleI // just to get hold of an EvalContext for it. ContextGraphWalker // caches its contexts, so we should get hold of the context that was // previously used for evaluation here, unless we skipped walking. - evalCtx := walker.EnterPath(moduleAddr) + evalCtx := walker.enterScope(evalContextModuleInstance{Addr: moduleAddr}) return evalCtx.EvaluationScope(nil, nil, EvalDataForNoInstanceKey) } diff --git a/internal/terraform/eval_context.go b/internal/terraform/eval_context.go index 47dbbf60d880..91b842b255ef 100644 --- a/internal/terraform/eval_context.go +++ b/internal/terraform/eval_context.go @@ -190,11 +190,13 @@ type EvalContext interface { // this execution. Overrides() *mocking.Overrides - // WithPath returns a copy of the context with the internal path set to the - // path argument. - WithPath(path addrs.ModuleInstance) EvalContext + // withScope derives a new EvalContext that has all of the same global + // context, but a new evaluation scope. + withScope(scope evalContextScope) EvalContext +} - // WithPartialExpandedPath returns a copy of the context with the internal - // path set to the path argument. - WithPartialExpandedPath(path addrs.PartialExpandedModule) EvalContext +func evalContextForModuleInstance(baseCtx EvalContext, addr addrs.ModuleInstance) EvalContext { + return baseCtx.withScope(evalContextModuleInstance{ + Addr: addr, + }) } diff --git a/internal/terraform/eval_context_builtin.go b/internal/terraform/eval_context_builtin.go index ac696a514e86..04c897012547 100644 --- a/internal/terraform/eval_context_builtin.go +++ b/internal/terraform/eval_context_builtin.go @@ -86,19 +86,9 @@ type BuiltinEvalContext struct { // BuiltinEvalContext implements EvalContext var _ EvalContext = (*BuiltinEvalContext)(nil) -func (ctx *BuiltinEvalContext) WithPath(path addrs.ModuleInstance) EvalContext { +func (ctx *BuiltinEvalContext) withScope(scope evalContextScope) EvalContext { newCtx := *ctx - newCtx.scope = evalContextModuleInstance{ - Addr: path, - } - return &newCtx -} - -func (ctx *BuiltinEvalContext) WithPartialExpandedPath(path addrs.PartialExpandedModule) EvalContext { - newCtx := *ctx - newCtx.scope = evalContextPartialExpandedModule{ - Addr: path, - } + newCtx.scope = scope return &newCtx } diff --git a/internal/terraform/eval_context_builtin_test.go b/internal/terraform/eval_context_builtin_test.go index 99ae1b8dd05a..42c443756e48 100644 --- a/internal/terraform/eval_context_builtin_test.go +++ b/internal/terraform/eval_context_builtin_test.go @@ -20,12 +20,12 @@ func TestBuiltinEvalContextProviderInput(t *testing.T) { cache := make(map[string]map[string]cty.Value) ctx1 := testBuiltinEvalContext(t) - ctx1 = ctx1.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext) + ctx1 = ctx1.withScope(evalContextModuleInstance{Addr: addrs.RootModuleInstance}).(*BuiltinEvalContext) ctx1.ProviderInputConfig = cache ctx1.ProviderLock = &lock ctx2 := testBuiltinEvalContext(t) - ctx2 = ctx2.WithPath(addrs.RootModuleInstance.Child("child", addrs.NoKey)).(*BuiltinEvalContext) + ctx2 = ctx2.withScope(evalContextModuleInstance{Addr: addrs.RootModuleInstance.Child("child", addrs.NoKey)}).(*BuiltinEvalContext) ctx2.ProviderInputConfig = cache ctx2.ProviderLock = &lock @@ -61,7 +61,7 @@ func TestBuildingEvalContextInitProvider(t *testing.T) { testP := &MockProvider{} ctx := testBuiltinEvalContext(t) - ctx = ctx.WithPath(addrs.RootModuleInstance).(*BuiltinEvalContext) + ctx = ctx.withScope(evalContextModuleInstance{Addr: addrs.RootModuleInstance}).(*BuiltinEvalContext) ctx.ProviderLock = &lock ctx.ProviderCache = make(map[string]providers.Interface) ctx.Plugins = newContextPlugins(map[addrs.Provider]providers.Factory{ diff --git a/internal/terraform/eval_context_mock.go b/internal/terraform/eval_context_mock.go index d96b89fc7360..ba6816e3751a 100644 --- a/internal/terraform/eval_context_mock.go +++ b/internal/terraform/eval_context_mock.go @@ -118,7 +118,7 @@ type MockEvalContext struct { EvaluationScopeScope *lang.Scope PathCalled bool - PathPath addrs.ModuleInstance + Scope evalContextScope LanguageExperimentsActive experiments.Set @@ -326,23 +326,18 @@ func (c *MockEvalContext) EvaluationScope(self addrs.Referenceable, source addrs return c.EvaluationScopeScope } -func (c *MockEvalContext) WithPath(path addrs.ModuleInstance) EvalContext { +func (c *MockEvalContext) withScope(scope evalContextScope) EvalContext { newC := *c - newC.PathPath = path + newC.Scope = scope return &newC } -func (c *MockEvalContext) WithPartialExpandedPath(path addrs.PartialExpandedModule) EvalContext { - // This is not yet implemented as a mock, because we've not yet had any - // need for it. If we end up needing to test this behavior in isolation - // somewhere then we'll need to figure out how to fit it in here without - // upsetting too many existing tests that rely on the PathPath field. - panic("WithPartialExpandedPath not implemented for MockEvalContext") -} - func (c *MockEvalContext) Path() addrs.ModuleInstance { c.PathCalled = true - return c.PathPath + // This intentionally panics if scope isn't a module instance; callers + // should use this only for an eval context that's working in a + // fully-expanded module instance. + return c.Scope.(evalContextModuleInstance).Addr } func (c *MockEvalContext) LanguageExperimentActive(experiment experiments.Experiment) bool { diff --git a/internal/terraform/eval_context_scope.go b/internal/terraform/eval_context_scope.go index 084835db7c2c..2e111e438e86 100644 --- a/internal/terraform/eval_context_scope.go +++ b/internal/terraform/eval_context_scope.go @@ -5,6 +5,7 @@ package terraform import ( "github.com/hashicorp/terraform/internal/addrs" + "github.com/hashicorp/terraform/internal/collections" ) // evalContextScope represents the scope that an [EvalContext] (or rather, @@ -26,6 +27,8 @@ import ( // a common known prefix, in situations where a module call has an unknown // value for its count or for_each argument. type evalContextScope interface { + collections.UniqueKeyer[evalContextScope] + // evalContextScopeModule returns the static module address of whatever // fully- or partially-expanded module instance address this scope is // associated with. @@ -33,6 +36,8 @@ type evalContextScope interface { // A "global" evaluation context is a nil [evalContextScope], and so // this method will panic for that scope. evalContextScopeModule() addrs.Module + + String() string } // evalContextGlobal is the nil [evalContextScope] used to represent an @@ -49,6 +54,16 @@ func (s evalContextModuleInstance) evalContextScopeModule() addrs.Module { return s.Addr.Module() } +func (s evalContextModuleInstance) String() string { + return s.Addr.String() +} + +func (s evalContextModuleInstance) UniqueKey() collections.UniqueKey[evalContextScope] { + return evalContextScopeUniqueKey{ + k: s.Addr.UniqueKey(), + } +} + // evalContextPartialExpandedModule is an [evalContextScope] associated with // an unbounded set of possible module instances that share a common known // address prefix. @@ -59,3 +74,20 @@ type evalContextPartialExpandedModule struct { func (s evalContextPartialExpandedModule) evalContextScopeModule() addrs.Module { return s.Addr.Module() } + +func (s evalContextPartialExpandedModule) String() string { + return s.Addr.String() +} + +func (s evalContextPartialExpandedModule) UniqueKey() collections.UniqueKey[evalContextScope] { + return evalContextScopeUniqueKey{ + k: s.Addr.UniqueKey(), + } +} + +type evalContextScopeUniqueKey struct { + k addrs.UniqueKey +} + +// IsUniqueKey implements collections.UniqueKey. +func (evalContextScopeUniqueKey) IsUniqueKey(evalContextScope) {} diff --git a/internal/terraform/eval_import.go b/internal/terraform/eval_import.go index aeebf37f3451..83e2b8c60488 100644 --- a/internal/terraform/eval_import.go +++ b/internal/terraform/eval_import.go @@ -21,7 +21,7 @@ func evaluateImportIdExpression(expr hcl.Expression, ctx EvalContext, keyData in // import blocks only exist in the root module, and must be evaluated in // that context. - ctx = ctx.WithPath(addrs.RootModuleInstance) + ctx = evalContextForModuleInstance(ctx, addrs.RootModuleInstance) if expr == nil { return "", diags.Append(&hcl.Diagnostic{ diff --git a/internal/terraform/graph.go b/internal/terraform/graph.go index e139f4533418..b4010874df36 100644 --- a/internal/terraform/graph.go +++ b/internal/terraform/graph.go @@ -76,21 +76,33 @@ func (g *Graph) walk(walker GraphWalker) tfdiags.Diagnostics { // vertexCtx is the context that we use when evaluating. This // is normally the global context but can be overridden - // with a GraphNodeModuleInstance or GraphNodePartialExpandedModule - // impl. (The two interfaces are intentionally mutually-exclusive by - // both having the same method name but with different signatures, - // since a node can't belong to two different contexts at once.) + // with either a GraphNodeModuleInstance, GraphNodePartialExpandedModule, + // or graphNodeEvalContextScope implementation. (These interfaces are + // all intentionally mutually-exclusive by having the same method + // name but different signatures, since a node can only belong to + // one context at a time.) vertexCtx := ctx - if pn, ok := v.(GraphNodeModuleInstance); ok { + if pn, ok := v.(graphNodeEvalContextScope); ok { + scope := pn.Path() + log.Printf("[TRACE] vertex %q: belongs to %s", dag.VertexName(v), scope) + vertexCtx = walker.enterScope(scope) + defer walker.exitScope(scope) + } else if pn, ok := v.(GraphNodeModuleInstance); ok { moduleAddr := pn.Path() // An addrs.ModuleInstance log.Printf("[TRACE] vertex %q: belongs to %s", dag.VertexName(v), moduleAddr) - vertexCtx = walker.EnterPath(moduleAddr) - defer walker.ExitPath(pn.Path()) + scope := evalContextModuleInstance{ + Addr: moduleAddr, + } + vertexCtx = walker.enterScope(scope) + defer walker.exitScope(scope) } else if pn, ok := v.(GraphNodePartialExpandedModule); ok { moduleAddr := pn.Path() // An addrs.PartialExpandedModule log.Printf("[TRACE] vertex %q: belongs to all of %s", dag.VertexName(v), moduleAddr) - vertexCtx = walker.EnterPartialExpandedPath(pn.Path()) - defer walker.ExitPartialExpandedPath(pn.Path()) + scope := evalContextPartialExpandedModule{ + Addr: moduleAddr, + } + vertexCtx = walker.enterScope(scope) + defer walker.exitScope(scope) } else { log.Printf("[TRACE] vertex %q: does not belong to any module instance", dag.VertexName(v)) } diff --git a/internal/terraform/graph_interface_subgraph.go b/internal/terraform/graph_interface_subgraph.go index f70fdeb84bd8..8f197591a60b 100644 --- a/internal/terraform/graph_interface_subgraph.go +++ b/internal/terraform/graph_interface_subgraph.go @@ -36,3 +36,17 @@ type GraphNodeModulePath interface { type GraphNodePartialExpandedModule interface { Path() addrs.PartialExpandedModule } + +// graphNodeEvalContextScope is essentially a combination of +// [GraphNodeModuleInstance] and [GraphNodePartialExpandedModule] for when +// the decision between the two must be made dynamically. +// +// When a graph node implements this interface, the [EvalContext] passed +// to its DynamicExpand and/or Execute method will be associated with whatever +// scope is returned by method Path. +type graphNodeEvalContextScope interface { + // Path must return a _non-nil_ evalContextScope value, which therefore + // describes either a fully-expanded module instance address or a + // partial-expanded module address. + Path() evalContextScope +} diff --git a/internal/terraform/graph_walk.go b/internal/terraform/graph_walk.go index 014ad1b36625..09886fc043c5 100644 --- a/internal/terraform/graph_walk.go +++ b/internal/terraform/graph_walk.go @@ -4,7 +4,6 @@ package terraform import ( - "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/tfdiags" ) @@ -12,10 +11,8 @@ import ( // with Graph.Walk will invoke the given callbacks under certain events. type GraphWalker interface { EvalContext() EvalContext - EnterPath(addrs.ModuleInstance) EvalContext - ExitPath(addrs.ModuleInstance) - EnterPartialExpandedPath(addrs.PartialExpandedModule) EvalContext - ExitPartialExpandedPath(addrs.PartialExpandedModule) + enterScope(evalContextScope) EvalContext + exitScope(evalContextScope) Execute(EvalContext, GraphNodeExecutable) tfdiags.Diagnostics } @@ -24,11 +21,7 @@ type GraphWalker interface { // implementing all the required functions. type NullGraphWalker struct{} -func (NullGraphWalker) EvalContext() EvalContext { return new(MockEvalContext) } -func (NullGraphWalker) EnterPath(addrs.ModuleInstance) EvalContext { return new(MockEvalContext) } -func (NullGraphWalker) ExitPath(addrs.ModuleInstance) {} -func (NullGraphWalker) EnterPartialExpandedPath(addrs.PartialExpandedModule) EvalContext { - return new(MockEvalContext) -} -func (NullGraphWalker) ExitPartialExpandedPath(addrs.PartialExpandedModule) {} +func (NullGraphWalker) EvalContext() EvalContext { return new(MockEvalContext) } +func (NullGraphWalker) enterScope(evalContextScope) EvalContext { return new(MockEvalContext) } +func (NullGraphWalker) exitScope(evalContextScope) {} func (NullGraphWalker) Execute(EvalContext, GraphNodeExecutable) tfdiags.Diagnostics { return nil } diff --git a/internal/terraform/graph_walk_context.go b/internal/terraform/graph_walk_context.go index 69150610149a..2aba9116c4c0 100644 --- a/internal/terraform/graph_walk_context.go +++ b/internal/terraform/graph_walk_context.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/checks" + "github.com/hashicorp/terraform/internal/collections" "github.com/hashicorp/terraform/internal/configs" "github.com/hashicorp/terraform/internal/configs/configschema" "github.com/hashicorp/terraform/internal/instances" @@ -51,7 +52,7 @@ type ContextGraphWalker struct { NonFatalDiagnostics tfdiags.Diagnostics once sync.Once - contexts map[string]*BuiltinEvalContext + contexts collections.Map[evalContextScope, *BuiltinEvalContext] contextLock sync.Mutex providerCache map[string]providers.Interface providerFuncCache map[string]providers.Interface @@ -65,33 +66,23 @@ type ContextGraphWalker struct { var _ GraphWalker = (*ContextGraphWalker)(nil) -func (w *ContextGraphWalker) EnterPath(path addrs.ModuleInstance) EvalContext { - w.contextLock.Lock() - defer w.contextLock.Unlock() - - // If we already have a context for this path cached, use that - key := path.String() - if ctx, ok := w.contexts[key]; ok { - return ctx +// enterScope provides an EvalContext associated with the given scope. +func (w *ContextGraphWalker) enterScope(scope evalContextScope) EvalContext { + if scope == nil { + // Just want a global EvalContext then, presumably. + return w.EvalContext() } - ctx := w.EvalContext().WithPath(path) - w.contexts[key] = ctx.(*BuiltinEvalContext) - return ctx -} - -func (w *ContextGraphWalker) EnterPartialExpandedPath(path addrs.PartialExpandedModule) EvalContext { w.contextLock.Lock() defer w.contextLock.Unlock() - // If we already have a context for this path cached, use that - key := path.String() - if ctx, ok := w.contexts[key]; ok { + // We might already have a context for this scope. + if ctx, ok := w.contexts.GetOk(scope); ok { return ctx } - ctx := w.EvalContext().WithPartialExpandedPath(path) - w.contexts[key] = ctx.(*BuiltinEvalContext) + ctx := w.EvalContext().withScope(scope).(*BuiltinEvalContext) + w.contexts.Put(scope, ctx) return ctx } @@ -142,7 +133,7 @@ func (w *ContextGraphWalker) EvalContext() EvalContext { } func (w *ContextGraphWalker) init() { - w.contexts = make(map[string]*BuiltinEvalContext) + w.contexts = collections.NewMap[evalContextScope, *BuiltinEvalContext]() w.providerCache = make(map[string]providers.Interface) w.providerFuncCache = make(map[string]providers.Interface) w.providerSchemas = make(map[string]providers.ProviderSchema) diff --git a/internal/terraform/node_module_expand.go b/internal/terraform/node_module_expand.go index f9cb8f46b37d..271703836ee0 100644 --- a/internal/terraform/node_module_expand.go +++ b/internal/terraform/node_module_expand.go @@ -103,8 +103,8 @@ func (n *nodeExpandModule) ReferenceOutside() (selfPath, referencePath addrs.Mod } // GraphNodeExecutable -func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { - expander := ctx.InstanceExpander() +func (n *nodeExpandModule) Execute(globalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { + expander := globalCtx.InstanceExpander() _, call := n.Addr.Call() // Allowing unknown values in count and for_each is currently only an @@ -114,16 +114,16 @@ func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) (diags tfd // If this is false then the codepaths that handle unknown values below // become unreachable, because the evaluate functions will reject unknown // values as an error. - allowUnknown := ctx.LanguageExperimentActive(experiments.UnknownInstances) + allowUnknown := globalCtx.LanguageExperimentActive(experiments.UnknownInstances) // nodeExpandModule itself does not have visibility into how its ancestors // were expanded, so we use the expander here to provide all possible paths // to our module, and register module instances with each of them. for _, module := range expander.ExpandModule(n.Addr.Parent()) { - ctx = ctx.WithPath(module) + moduleCtx := evalContextForModuleInstance(globalCtx, module) switch { case n.ModuleCall.Count != nil: - count, ctDiags := evaluateCountExpression(n.ModuleCall.Count, ctx, allowUnknown) + count, ctDiags := evaluateCountExpression(n.ModuleCall.Count, moduleCtx, allowUnknown) diags = diags.Append(ctDiags) if diags.HasErrors() { return diags @@ -136,7 +136,7 @@ func (n *nodeExpandModule) Execute(ctx EvalContext, op walkOperation) (diags tfd } case n.ModuleCall.ForEach != nil: - forEach, known, feDiags := evaluateForEachExpression(n.ModuleCall.ForEach, ctx, allowUnknown) + forEach, known, feDiags := evaluateForEachExpression(n.ModuleCall.ForEach, moduleCtx, allowUnknown) diags = diags.Append(feDiags) if diags.HasErrors() { return diags @@ -255,31 +255,31 @@ type nodeValidateModule struct { var _ GraphNodeExecutable = (*nodeValidateModule)(nil) // GraphNodeEvalable -func (n *nodeValidateModule) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { +func (n *nodeValidateModule) Execute(globalCtx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { _, call := n.Addr.Call() - expander := ctx.InstanceExpander() + expander := globalCtx.InstanceExpander() // Modules all evaluate to single instances during validation, only to // create a proper context within which to evaluate. All parent modules // will be a single instance, but still get our address in the expected // manner anyway to ensure they've been registered correctly. for _, module := range expander.ExpandModule(n.Addr.Parent()) { - ctx = ctx.WithPath(module) + moduleCtx := evalContextForModuleInstance(globalCtx, module) // Validate our for_each and count expressions at a basic level // We skip validation on known, because there will be unknown values before // a full expansion, presuming these errors will be caught in later steps switch { case n.ModuleCall.Count != nil: - _, countDiags := evaluateCountExpressionValue(n.ModuleCall.Count, ctx) + _, countDiags := evaluateCountExpressionValue(n.ModuleCall.Count, moduleCtx) diags = diags.Append(countDiags) case n.ModuleCall.ForEach != nil: - forEachDiags := newForEachEvaluator(n.ModuleCall.ForEach, ctx, false).ValidateResourceValue() + forEachDiags := newForEachEvaluator(n.ModuleCall.ForEach, moduleCtx, false).ValidateResourceValue() diags = diags.Append(forEachDiags) } - diags = diags.Append(validateDependsOn(ctx, n.ModuleCall.DependsOn)) + diags = diags.Append(validateDependsOn(moduleCtx, n.ModuleCall.DependsOn)) // now set our own mode to single expander.SetModuleSingle(module, call) diff --git a/internal/terraform/node_resource_abstract_instance_test.go b/internal/terraform/node_resource_abstract_instance_test.go index 07ff05da374b..eb7230189e84 100644 --- a/internal/terraform/node_resource_abstract_instance_test.go +++ b/internal/terraform/node_resource_abstract_instance_test.go @@ -145,7 +145,7 @@ func TestNodeAbstractResourceInstance_WriteResourceInstanceState(t *testing.T) { state := states.NewState() ctx := new(MockEvalContext) ctx.StateState = state.SyncWrapper() - ctx.PathPath = addrs.RootModuleInstance + ctx.Scope = evalContextModuleInstance{Addr: addrs.RootModuleInstance} mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ Attributes: map[string]*configschema.Attribute{ diff --git a/internal/terraform/node_resource_abstract_test.go b/internal/terraform/node_resource_abstract_test.go index e04456192d27..cd196128f217 100644 --- a/internal/terraform/node_resource_abstract_test.go +++ b/internal/terraform/node_resource_abstract_test.go @@ -229,7 +229,7 @@ func TestNodeAbstractResource_ReadResourceInstanceState(t *testing.T) { t.Run(k, func(t *testing.T) { ctx := new(MockEvalContext) ctx.StateState = test.State.SyncWrapper() - ctx.PathPath = addrs.RootModuleInstance + ctx.Scope = evalContextModuleInstance{Addr: addrs.RootModuleInstance} ctx.ProviderSchemaSchema = mockProvider.GetProviderSchema() ctx.ProviderProvider = providers.Interface(mockProvider) @@ -294,7 +294,7 @@ func TestNodeAbstractResource_ReadResourceInstanceStateDeposed(t *testing.T) { t.Run(k, func(t *testing.T) { ctx := new(MockEvalContext) ctx.StateState = test.State.SyncWrapper() - ctx.PathPath = addrs.RootModuleInstance + ctx.Scope = evalContextModuleInstance{Addr: addrs.RootModuleInstance} ctx.ProviderSchemaSchema = mockProvider.GetProviderSchema() ctx.ProviderProvider = providers.Interface(mockProvider) diff --git a/internal/terraform/node_resource_apply.go b/internal/terraform/node_resource_apply.go index 738ab9e50fde..9dd3f52c4dfb 100644 --- a/internal/terraform/node_resource_apply.go +++ b/internal/terraform/node_resource_apply.go @@ -46,13 +46,13 @@ func (n *nodeExpandApplyableResource) Name() string { return n.NodeAbstractResource.Name() + " (expand)" } -func (n *nodeExpandApplyableResource) Execute(ctx EvalContext, op walkOperation) tfdiags.Diagnostics { +func (n *nodeExpandApplyableResource) Execute(globalCtx EvalContext, op walkOperation) tfdiags.Diagnostics { var diags tfdiags.Diagnostics - expander := ctx.InstanceExpander() + expander := globalCtx.InstanceExpander() moduleInstances := expander.ExpandModule(n.Addr.Module) for _, module := range moduleInstances { - ctx = ctx.WithPath(module) - diags = diags.Append(n.writeResourceState(ctx, n.Addr.Resource.Absolute(module))) + moduleCtx := evalContextForModuleInstance(globalCtx, module) + diags = diags.Append(n.writeResourceState(moduleCtx, n.Addr.Resource.Absolute(module))) } return diags diff --git a/internal/terraform/node_resource_destroy_deposed_test.go b/internal/terraform/node_resource_destroy_deposed_test.go index 7ea118aaab37..722563beabdf 100644 --- a/internal/terraform/node_resource_destroy_deposed_test.go +++ b/internal/terraform/node_resource_destroy_deposed_test.go @@ -153,7 +153,7 @@ func TestNodeDestroyDeposedResourceInstanceObject_WriteResourceInstanceState(t * state := states.NewState() ctx := new(MockEvalContext) ctx.StateState = state.SyncWrapper() - ctx.PathPath = addrs.RootModuleInstance + ctx.Scope = evalContextModuleInstance{Addr: addrs.RootModuleInstance} mockProvider := mockProviderWithResourceTypeSchema("aws_instance", &configschema.Block{ Attributes: map[string]*configschema.Attribute{ "id": { diff --git a/internal/terraform/node_resource_plan.go b/internal/terraform/node_resource_plan.go index 8825160c41d0..18bcb2483bfa 100644 --- a/internal/terraform/node_resource_plan.go +++ b/internal/terraform/node_resource_plan.go @@ -230,7 +230,7 @@ func (n *nodeExpandPlannableResource) expandResourceInstances(globalCtx EvalCont // The rest of our work here needs to know which module instance it's // working in, so that it can evaluate expressions in the appropriate scope. - moduleCtx := globalCtx.WithPath(resAddr.Module) + moduleCtx := evalContextForModuleInstance(globalCtx, resAddr.Module) // writeResourceState is responsible for informing the expander of what // repetition mode this resource has, which allows expander.ExpandResource @@ -339,7 +339,7 @@ func (n nodeExpandPlannableResource) expandResourceImports(ctx EvalContext, addr // Import blocks are only valid within the root module, and must be // evaluated within that context - ctx = ctx.WithPath(addrs.RootModuleInstance) + ctx = evalContextForModuleInstance(ctx, addrs.RootModuleInstance) for _, imp := range n.importTargets { if imp.Config == nil { diff --git a/internal/terraform/transform_import_state_test.go b/internal/terraform/transform_import_state_test.go index 89fdc3944b19..70fb416cfb01 100644 --- a/internal/terraform/transform_import_state_test.go +++ b/internal/terraform/transform_import_state_test.go @@ -30,6 +30,7 @@ func TestGraphNodeImportStateExecute(t *testing.T) { provider.ConfigureProvider(providers.ConfigureProviderRequest{}) ctx := &MockEvalContext{ + Scope: evalContextModuleInstance{Addr: addrs.RootModuleInstance}, StateState: state.SyncWrapper(), ProviderProvider: provider, }