package types
import (
- "bytes"
- "fmt"
"sort"
"cmd/compile/internal/base"
return o
}
-// findTypeLoop searches for an invalid type declaration loop involving
-// type t and reports whether one is found. If so, path contains the
-// loop.
-//
-// path points to a slice used for tracking the sequence of types
-// visited. Using a pointer to a slice allows the slice capacity to
-// grow and limit reallocations.
-func findTypeLoop(t *Type, path *[]*Type) bool {
- // We implement a simple DFS loop-finding algorithm. This
- // could be faster, but type cycles are rare.
-
- if t.Sym() != nil {
- // Declared type. Check for loops and otherwise
- // recurse on the type expression used in the type
- // declaration.
-
- // Type imported from package, so it can't be part of
- // a type loop (otherwise that package should have
- // failed to compile).
- if t.Sym().Pkg != LocalPkg {
- return false
- }
-
- for i, x := range *path {
- if x == t {
- *path = (*path)[i:]
- return true
- }
- }
-
- *path = append(*path, t)
- if findTypeLoop(t.Obj().(TypeObject).TypeDefn(), path) {
- return true
- }
- *path = (*path)[:len(*path)-1]
- } else {
- // Anonymous type. Recurse on contained types.
-
- switch t.Kind() {
- case TARRAY:
- if findTypeLoop(t.Elem(), path) {
- return true
- }
- case TSTRUCT:
- for _, f := range t.Fields().Slice() {
- if findTypeLoop(f.Type, path) {
- return true
- }
- }
- case TINTER:
- for _, m := range t.Methods().Slice() {
- if m.Type.IsInterface() { // embedded interface
- if findTypeLoop(m.Type, path) {
- return true
- }
- }
- }
- }
- }
-
- return false
-}
-
-func reportTypeLoop(t *Type) {
- var l []*Type
- if !findTypeLoop(t, &l) {
- base.Fatalf("failed to find type loop for: %v", t)
- }
-
- // Rotate loop so that the earliest type declaration is first.
- i := 0
- for j, t := range l[1:] {
- if typePos(t).Before(typePos(l[i])) {
- i = j + 1
- }
- }
- l = append(l[i:], l[:i]...)
-
- var msg bytes.Buffer
- fmt.Fprintf(&msg, "invalid recursive type %v\n", l[0])
- for _, t := range l {
- fmt.Fprintf(&msg, "\t%v: %v refers to\n", base.FmtPos(typePos(t)), t)
- t.SetBroke(true)
- }
- fmt.Fprintf(&msg, "\t%v: %v", base.FmtPos(typePos(l[0])), l[0])
- base.ErrorfAt(typePos(l[0]), msg.String())
-}
-
// CalcSize calculates and stores the size and alignment for t.
// If CalcSizeDisabled is set, and the size/alignment
// have not already been calculated, it calls Fatal.
}
if t.width == -2 {
- reportTypeLoop(t)
t.width = 0
t.align = 1
+ base.Fatalf("invalid recursive type %v", t)
return
}
CheckSize(t.Key())
case TFORW: // should have been filled in
- reportTypeLoop(t)
+ base.Fatalf("invalid recursive type %v", t)
w = 1 // anything will do
case TANY: