// checkStaticDependencyCycle checks the given variable/field node for a initialization dependency // cycle. func (sb *scopeBuilder) checkStaticDependencyCycle(varNode compilergraph.GraphNode, currentDep *proto.ScopeReference, encountered *ordered_map.OrderedMap, path []typegraph.TGMember) bool { // If we've already examined this dependency, nothing else to do. if _, found := encountered.Get(currentDep.GetReferencedNode()); found { return true } encountered.Set(currentDep.GetReferencedNode(), true) // Lookup the dependency (which is a type or module member) in the type graph. memberNodeId := compilergraph.GraphNodeId(currentDep.GetReferencedNode()) member := sb.sg.tdg.GetTypeOrMember(memberNodeId) // Find the associated source node. sourceNodeId, hasSourceNode := member.SourceNodeId() if !hasSourceNode { return true } updatedPath := append([]typegraph.TGMember(nil), path...) updatedPath = append(updatedPath, member.(typegraph.TGMember)) // If we've found the variable itself, then we have a dependency cycle. if sourceNodeId == varNode.GetNodeId() { // Found a cycle. var chain bytes.Buffer chain.WriteString(member.Title()) chain.WriteRune(' ') chain.WriteString(member.Name()) for _, cMember := range updatedPath { chain.WriteString(" -> ") chain.WriteString(cMember.Title()) chain.WriteRune(' ') chain.WriteString(cMember.Name()) } sb.decorateWithError(varNode, "Initialization cycle found on %v %v: %s", member.Title(), member.Name(), chain.String()) sb.Status = false return false } // Lookup the dependency in the SRG, so we can recursively check *its* dependencies. srgNode, hasSRGNode := sb.sg.srg.TryGetNode(sourceNodeId) if !hasSRGNode { return true } // Recursively lookup the static deps for the node and check them. nodeScope := sb.getScopeForRootNode(srgNode) for _, staticDep := range nodeScope.GetStaticDependencies() { if !sb.checkStaticDependencyCycle(varNode, staticDep, encountered, updatedPath) { return false } } return true }