// NOTE: It'd be pretty weird to _not_ have a range, since
// we're only in this codepath because the plan phase
// thought this object existed in the configuration.
declaredAt=fmt.Sprintf(" at %s",conflictRange.StartString())
}
diags=diags.Append(&hcl.Diagnostic{
Severity:hcl.DiagError,
Summary:"Moved object still exists",
Detail:fmt.Sprintf(
"This statement declares a move from %s, but that %s is still declared%s.\n\nChange your configuration so that this %s will be declared as %s instead.",
absFrom,noun,declaredAt,shortNoun,absTo,
),
Subject:stmt.DeclRange.ToHCL().Ptr(),
})
}
// There can only be one destination for each source address.
ifexisting,exists:=stmtFrom[fromKey];exists{
ifexisting.Other.UniqueKey()!=toKey{
diags=diags.Append(&hcl.Diagnostic{
Severity:hcl.DiagError,
Summary:"Ambiguous move statements",
Detail:fmt.Sprintf(
"A statement at %s declared that %s moved to %s, but this statement instead declares that it moved to %s.\n\nEach %s can move to only one destination %s.",
// There can only be one source for each destination address.
ifexisting,exists:=stmtTo[toKey];exists{
ifexisting.Other.UniqueKey()!=fromKey{
diags=diags.Append(&hcl.Diagnostic{
Severity:hcl.DiagError,
Summary:"Ambiguous move statements",
Detail:fmt.Sprintf(
"A statement at %s declared that %s moved to %s, but this statement instead declares that %s moved there.\n\nEach %s can have moved from only one source %s.",
// If we're not already returning other errors then we'll also check for
// and report cycles.
//
// Cycles alone are difficult to report in a helpful way because we don't
// have enough context to guess the user's intent. However, some particular
// mistakes that might lead to a cycle can also be caught by other
// validation rules above where we can make better suggestions, and so
// we'll use a cycle report only as a last resort.
if!diags.HasErrors(){
for_,cycle:=rangeg.Cycles(){
// Reporting cycles is awkward because there isn't any definitive
// way to decide which of the objects in the cycle is the cause of
// the problem. Therefore we'll just list them all out and leave
// the user to figure it out. :(
stmtStrs:=make([]string,0,len(cycle))
for_,stmtI:=rangecycle{
// move statement graph nodes are pointers to move statements
stmt:=stmtI.(*MoveStatement)
stmtStrs=append(stmtStrs,fmt.Sprintf(
"\n - %s: %s → %s",
stmt.DeclRange.StartString(),
stmt.From.String(),
stmt.To.String(),
))
}
sort.Strings(stmtStrs)// just to make the order deterministic
diags=diags.Append(tfdiags.Sourceless(
tfdiags.Error,
"Cyclic dependency in move statements",
fmt.Sprintf(
"The following chained move statements form a cycle, and so there is no final location to move objects to:%s\n\nA chain of move statements must end with an address that doesn't appear in any other statements, and which typically also refers to an object still declared in the configuration.",