case typexpr:
// don't crash for "type T T.x" (was go.dev/issue/51509)
if def != nil && def.typ == x.typ {
- check.cycleError([]Object{def})
+ check.cycleError([]Object{def}, 0)
goto Error
}
case builtin:
}
}
- check.cycleError(cycle)
+ check.cycleError(cycle, firstInSrc(cycle))
return false
}
-// cycleError reports a declaration cycle starting with
-// the object in cycle that is "first" in the source.
-func (check *Checker) cycleError(cycle []Object) {
+// cycleError reports a declaration cycle starting with the object at cycle[start].
+func (check *Checker) cycleError(cycle []Object, start int) {
// name returns the (possibly qualified) object name.
// This is needed because with generic types, cycles
// may refer to imported types. See go.dev/issue/50788.
return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
}
- // TODO(gri) Should we start with the last (rather than the first) object in the cycle
- // since that is the earliest point in the source where we start seeing the
- // cycle? That would be more consistent with other error messages.
- i := firstInSrc(cycle)
- obj := cycle[i]
+ obj := cycle[start]
objName := name(obj)
// If obj is a type alias, mark it as valid (not broken) in order to avoid follow-on errors.
tname, _ := obj.(*TypeName)
} else {
err.addf(obj, "invalid cycle in declaration of %s", objName)
}
+ i := start
for range cycle {
err.addf(obj, "%s refers to", objName)
i++
n = n1
if i, ok := seen[n]; ok {
// cycle
- check.cycleError(path[i:])
+ check.cycleError(path[i:], firstInSrc(path[i:]))
u = Typ[Invalid]
break
}
// index of t in nest. Search again.
for start, p := range path {
if Identical(p, t) {
- check.cycleError(makeObjList(path[start:]))
+ check.cycleError(makeObjList(path[start:]), 0)
return false
}
}
case typexpr:
// don't crash for "type T T.x" (was go.dev/issue/51509)
if def != nil && def.typ == x.typ {
- check.cycleError([]Object{def})
+ check.cycleError([]Object{def}, 0)
goto Error
}
case builtin:
}
}
- check.cycleError(cycle)
+ check.cycleError(cycle, firstInSrc(cycle))
return false
}
-// cycleError reports a declaration cycle starting with
-// the object in cycle that is "first" in the source.
-func (check *Checker) cycleError(cycle []Object) {
+// cycleError reports a declaration cycle starting with the object at cycle[start].
+func (check *Checker) cycleError(cycle []Object, start int) {
// name returns the (possibly qualified) object name.
// This is needed because with generic types, cycles
// may refer to imported types. See go.dev/issue/50788.
return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
}
- // TODO(gri) Should we start with the last (rather than the first) object in the cycle
- // since that is the earliest point in the source where we start seeing the
- // cycle? That would be more consistent with other error messages.
- i := firstInSrc(cycle)
- obj := cycle[i]
+ obj := cycle[start]
objName := name(obj)
// If obj is a type alias, mark it as valid (not broken) in order to avoid follow-on errors.
tname, _ := obj.(*TypeName)
} else {
check.errorf(obj, InvalidDeclCycle, "invalid cycle in declaration of %s", objName)
}
+ i := start
for range cycle {
check.errorf(obj, InvalidDeclCycle, "\t%s refers to", objName) // secondary error, \t indented
i++
n = n1
if i, ok := seen[n]; ok {
// cycle
- check.cycleError(path[i:])
+ check.cycleError(path[i:], firstInSrc(path[i:]))
u = Typ[Invalid]
break
}
// index of t in nest. Search again.
for start, p := range path {
if Identical(p, t) {
- check.cycleError(makeObjList(path[start:]))
+ check.cycleError(makeObjList(path[start:]), 0)
return false
}
}
type A[P any] [1]P
-type B[P any] A /* ERROR "invalid recursive type" */ [P]
+type B[P any] A[P]
-type C B[C]
+type C /* ERROR "invalid recursive type" */ B[C]
// test case from issue
}
type Bar[T any] struct {
- foo Foo /* ERROR "invalid recursive type" */ [T]
+ foo Foo[T]
}
-type Baz struct {
+type Baz /* ERROR "invalid recursive type" */ struct {
bar Bar[Baz]
}