// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
// Source: ../../cmd/compile/internal/types2/cycles.go

// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package types

import 

// directCycles searches for direct cycles among package level type declarations.
// See directCycle for details.
func ( *Checker) () {
	 := make(map[*TypeName]int)
	for ,  := range .objList {
		if ,  := .(*TypeName);  {
			.directCycle(, )
		}
	}
}

// directCycle checks if the declaration of the type given by tname contains a direct cycle.
// A direct cycle exists if the path from tname's declaration's RHS leads from type name to
// type name and eventually ends up on that path again, via regular or alias declarations;
// in other words if there are no type literals (or basic types) on the path, and the path
// doesn't end in an undeclared object.
// If a cycle is detected, a cycle error is reported and the type at the start of the cycle
// is marked as invalid.
//
// The pathIdx map tracks which type names have been processed. An entry can be
// in 1 of 3 states as used in a typical 3-state (white/grey/black) graph marking
// algorithm for cycle detection:
//
//   - entry not found: tname has not been seen before (white)
//   - value is >= 0  : tname has been seen but is not done (grey); the value is the path index
//   - value is <  0  : tname has been seen and is done (black)
//
// When directCycle returns, the pathIdx entries for all type names on the path
// that starts at tname are marked black, regardless of whether there was a cycle.
// This ensures that a type name is traversed only once.
func ( *Checker) ( *TypeName,  map[*TypeName]int) {
	if debug && .conf._Trace {
		.trace(.Pos(), "-- check direct cycle for %s", )
	}

	var  []*TypeName
	for {
		,  := []
		if  < 0 {
			// tname is marked black - do not traverse it again.
			// (start can only be < 0 if it was found in the first place)
			break
		}

		if  {
			// tname is marked grey - we have a cycle on the path beginning at start.
			// Mark tname as invalid.
			.setType(Typ[Invalid])

			// collect type names on cycle
			var  []Object
			for ,  := range [:] {
				 = append(, )
			}

			.cycleError(, firstInSrc())
			break
		}

		// tname is marked white - mark it grey and add it to the path.
		[] = len()
		 = append(, )

		// For direct cycle detection, we don't care about whether we have an alias or not.
		// If the associated type is not a name, we're at the end of the path and we're done.
		,  := .objMap[].tdecl.Type.(*ast.Ident)
		if ! {
			break
		}

		// Determine the RHS type. If it is not found in the package scope, we either
		// have an error (which will be reported later), or the type exists elsewhere
		// (universe scope, file scope via dot-import) and a cycle is not possible in
		// the first place. If it is not a type name, we cannot have a direct cycle
		// either. In all these cases we can stop.
		,  := .pkg.scope.Lookup(.Name).(*TypeName)
		if ! {
			break
		}

		// Otherwise, continue with the RHS.
		 = 
	}

	// Mark all traversed type names black.
	// (ensure that pathIdx doesn't contain any grey entries upon returning)
	for ,  := range  {
		[] = -1
	}

	if debug {
		for ,  := range  {
			assert( < 0)
		}
	}
}

// TODO(markfreeman): Can the value cached on Named be used in validType / hasVarSize?

// finiteSize returns whether a type has finite size.
func ( *Checker) ( Type) bool {
	switch t := Unalias().(type) {
	case *Named:
		if .stateHas(hasFinite) {
			return .finite
		}

		if ,  := .objPathIdx[.obj];  {
			 := .objPath[:]
			.cycleError(, firstInSrc())
			return false
		}
		.push(.obj)
		defer .pop()

		 := .(.fromRHS)

		.mu.Lock()
		defer .mu.Unlock()
		// Careful, t.finite has lock-free readers. Since we might be racing
		// another call to finiteSize, we have to avoid overwriting t.finite.
		// Otherwise, the race detector will be tripped.
		if !.stateHas(hasFinite) {
			.finite = 
			.setState(hasFinite)
		}

		return 

	case *Array:
		// The array length is already computed. If it was a valid length, it
		// is finite; else, an error was reported in the computation.
		return .(.elem)

	case *Struct:
		for ,  := range .fields {
			if !.(.typ) {
				return false
			}
		}
	}

	return true
}