diff --git a/internal/refactoring/move_validate.go b/internal/refactoring/move_validate.go index eedf00414..13f2e50f9 100644 --- a/internal/refactoring/move_validate.go +++ b/internal/refactoring/move_validate.go @@ -55,27 +55,34 @@ func ValidateMoves(stmts []MoveStatement, rootCfg *configs.Config, declaredInsts _, toCallSteps := stmt.To.ModuleCallTraversals() modCfg := rootCfg.Descendent(stmtMod) - if pkgAddr := callsThroughModulePackage(modCfg, fromCallSteps); pkgAddr != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Cross-package move statement", - Detail: fmt.Sprintf( - "This statement declares a move from an object declared in external module package %q. Move statements can be only within a single module package.", - pkgAddr, - ), - Subject: stmt.DeclRange.ToHCL().Ptr(), - }) - } - if pkgAddr := callsThroughModulePackage(modCfg, toCallSteps); pkgAddr != nil { - diags = diags.Append(&hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Cross-package move statement", - Detail: fmt.Sprintf( - "This statement declares a move to an object declared in external module package %q. Move statements can be only within a single module package.", - pkgAddr, - ), - Subject: stmt.DeclRange.ToHCL().Ptr(), - }) + if !stmt.Implied { + // Implied statements can cross module boundaries because we + // generate them only for changing instance keys on a single + // resource. They happen to be generated _as if_ they were written + // in the root module, but the source and destination are always + // in the same module anyway. + if pkgAddr := callsThroughModulePackage(modCfg, fromCallSteps); pkgAddr != nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Cross-package move statement", + Detail: fmt.Sprintf( + "This statement declares a move from an object declared in external module package %q. Move statements can be only within a single module package.", + pkgAddr, + ), + Subject: stmt.DeclRange.ToHCL().Ptr(), + }) + } + if pkgAddr := callsThroughModulePackage(modCfg, toCallSteps); pkgAddr != nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Cross-package move statement", + Detail: fmt.Sprintf( + "This statement declares a move to an object declared in external module package %q. Move statements can be only within a single module package.", + pkgAddr, + ), + Subject: stmt.DeclRange.ToHCL().Ptr(), + }) + } } for _, modInst := range declaredInsts.InstancesForModule(stmtMod) { diff --git a/internal/refactoring/move_validate_test.go b/internal/refactoring/move_validate_test.go index 60122511f..aa4ec4f3b 100644 --- a/internal/refactoring/move_validate_test.go +++ b/internal/refactoring/move_validate_test.go @@ -366,6 +366,50 @@ Each resource can have moved from only one source resource.`, }, WantError: `Cross-package move statement: This statement declares a move to an object declared in external module package "fake-external:///". Move statements can be only within a single module package.`, }, + "implied move from resource in another module package": { + Statements: []MoveStatement{ + makeTestImpliedMoveStmt(t, + ``, + `module.fake_external.test.thing`, + `test.thing`, + ), + }, + // Implied move statements are not subject to the cross-package restriction + WantError: ``, + }, + "implied move to resource in another module package": { + Statements: []MoveStatement{ + makeTestImpliedMoveStmt(t, + ``, + `test.thing`, + `module.fake_external.test.thing`, + ), + }, + // Implied move statements are not subject to the cross-package restriction + WantError: ``, + }, + "implied move from module call in another module package": { + Statements: []MoveStatement{ + makeTestImpliedMoveStmt(t, + ``, + `module.fake_external.module.a`, + `module.b`, + ), + }, + // Implied move statements are not subject to the cross-package restriction + WantError: ``, + }, + "implied move to module call in another module package": { + Statements: []MoveStatement{ + makeTestImpliedMoveStmt(t, + ``, + `module.a`, + `module.fake_external.module.b`, + ), + }, + // Implied move statements are not subject to the cross-package restriction + WantError: ``, + }, "move to a call that refers to another module package": { Statements: []MoveStatement{ makeTestMoveStmt(t, @@ -650,6 +694,13 @@ func makeTestMoveStmt(t *testing.T, moduleStr, fromStr, toStr string) MoveStatem } } +func makeTestImpliedMoveStmt(t *testing.T, moduleStr, fromStr, toStr string) MoveStatement { + t.Helper() + ret := makeTestMoveStmt(t, moduleStr, fromStr, toStr) + ret.Implied = true + return ret +} + var fakeExternalModuleSource = addrs.ModuleSourceRemote{ PackageAddr: addrs.ModulePackage("fake-external:///"), }