mirror of
https://github.com/golang/go
synced 2024-09-28 21:24:29 -06:00
go/types, types2: better error position for invalid (infinite) types
Provide an explicit start position to Checker.cycleError for better control over the reported error. For #65711. Change-Id: Ie3016523442d75f348a033c1b944db493943f433 Reviewed-on: https://go-review.googlesource.com/c/go/+/567916 Auto-Submit: Robert Griesemer <gri@google.com> Reviewed-by: Robert Findley <rfindley@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
9f9008ce66
commit
13e5fd95f5
@ -767,7 +767,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *TypeName
|
|||||||
case typexpr:
|
case typexpr:
|
||||||
// don't crash for "type T T.x" (was go.dev/issue/51509)
|
// don't crash for "type T T.x" (was go.dev/issue/51509)
|
||||||
if def != nil && def.typ == x.typ {
|
if def != nil && def.typ == x.typ {
|
||||||
check.cycleError([]Object{def})
|
check.cycleError([]Object{def}, 0)
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
case builtin:
|
case builtin:
|
||||||
|
@ -301,13 +301,12 @@ loop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check.cycleError(cycle)
|
check.cycleError(cycle, firstInSrc(cycle))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// cycleError reports a declaration cycle starting with
|
// cycleError reports a declaration cycle starting with the object at cycle[start].
|
||||||
// the object in cycle that is "first" in the source.
|
func (check *Checker) cycleError(cycle []Object, start int) {
|
||||||
func (check *Checker) cycleError(cycle []Object) {
|
|
||||||
// name returns the (possibly qualified) object name.
|
// name returns the (possibly qualified) object name.
|
||||||
// This is needed because with generic types, cycles
|
// This is needed because with generic types, cycles
|
||||||
// may refer to imported types. See go.dev/issue/50788.
|
// may refer to imported types. See go.dev/issue/50788.
|
||||||
@ -316,11 +315,7 @@ func (check *Checker) cycleError(cycle []Object) {
|
|||||||
return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
|
return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gri) Should we start with the last (rather than the first) object in the cycle
|
obj := cycle[start]
|
||||||
// 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]
|
|
||||||
objName := name(obj)
|
objName := name(obj)
|
||||||
// If obj is a type alias, mark it as valid (not broken) in order to avoid follow-on errors.
|
// If obj is a type alias, mark it as valid (not broken) in order to avoid follow-on errors.
|
||||||
tname, _ := obj.(*TypeName)
|
tname, _ := obj.(*TypeName)
|
||||||
@ -348,6 +343,7 @@ func (check *Checker) cycleError(cycle []Object) {
|
|||||||
} else {
|
} else {
|
||||||
err.addf(obj, "invalid cycle in declaration of %s", objName)
|
err.addf(obj, "invalid cycle in declaration of %s", objName)
|
||||||
}
|
}
|
||||||
|
i := start
|
||||||
for range cycle {
|
for range cycle {
|
||||||
err.addf(obj, "%s refers to", objName)
|
err.addf(obj, "%s refers to", objName)
|
||||||
i++
|
i++
|
||||||
|
@ -552,7 +552,7 @@ loop:
|
|||||||
n = n1
|
n = n1
|
||||||
if i, ok := seen[n]; ok {
|
if i, ok := seen[n]; ok {
|
||||||
// cycle
|
// cycle
|
||||||
check.cycleError(path[i:])
|
check.cycleError(path[i:], firstInSrc(path[i:]))
|
||||||
u = Typ[Invalid]
|
u = Typ[Invalid]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ func (check *Checker) validType0(pos syntax.Pos, typ Type, nest, path []*Named)
|
|||||||
// index of t in nest. Search again.
|
// index of t in nest. Search again.
|
||||||
for start, p := range path {
|
for start, p := range path {
|
||||||
if Identical(p, t) {
|
if Identical(p, t) {
|
||||||
check.cycleError(makeObjList(path[start:]))
|
check.cycleError(makeObjList(path[start:]), 0)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -770,7 +770,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w
|
|||||||
case typexpr:
|
case typexpr:
|
||||||
// don't crash for "type T T.x" (was go.dev/issue/51509)
|
// don't crash for "type T T.x" (was go.dev/issue/51509)
|
||||||
if def != nil && def.typ == x.typ {
|
if def != nil && def.typ == x.typ {
|
||||||
check.cycleError([]Object{def})
|
check.cycleError([]Object{def}, 0)
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
case builtin:
|
case builtin:
|
||||||
|
@ -300,13 +300,12 @@ loop:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check.cycleError(cycle)
|
check.cycleError(cycle, firstInSrc(cycle))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// cycleError reports a declaration cycle starting with
|
// cycleError reports a declaration cycle starting with the object at cycle[start].
|
||||||
// the object in cycle that is "first" in the source.
|
func (check *Checker) cycleError(cycle []Object, start int) {
|
||||||
func (check *Checker) cycleError(cycle []Object) {
|
|
||||||
// name returns the (possibly qualified) object name.
|
// name returns the (possibly qualified) object name.
|
||||||
// This is needed because with generic types, cycles
|
// This is needed because with generic types, cycles
|
||||||
// may refer to imported types. See go.dev/issue/50788.
|
// may refer to imported types. See go.dev/issue/50788.
|
||||||
@ -315,11 +314,7 @@ func (check *Checker) cycleError(cycle []Object) {
|
|||||||
return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
|
return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(gri) Should we start with the last (rather than the first) object in the cycle
|
obj := cycle[start]
|
||||||
// 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]
|
|
||||||
objName := name(obj)
|
objName := name(obj)
|
||||||
// If obj is a type alias, mark it as valid (not broken) in order to avoid follow-on errors.
|
// If obj is a type alias, mark it as valid (not broken) in order to avoid follow-on errors.
|
||||||
tname, _ := obj.(*TypeName)
|
tname, _ := obj.(*TypeName)
|
||||||
@ -346,6 +341,7 @@ func (check *Checker) cycleError(cycle []Object) {
|
|||||||
} else {
|
} else {
|
||||||
check.errorf(obj, InvalidDeclCycle, "invalid cycle in declaration of %s", objName)
|
check.errorf(obj, InvalidDeclCycle, "invalid cycle in declaration of %s", objName)
|
||||||
}
|
}
|
||||||
|
i := start
|
||||||
for range cycle {
|
for range cycle {
|
||||||
check.errorf(obj, InvalidDeclCycle, "\t%s refers to", objName) // secondary error, \t indented
|
check.errorf(obj, InvalidDeclCycle, "\t%s refers to", objName) // secondary error, \t indented
|
||||||
i++
|
i++
|
||||||
|
@ -554,7 +554,7 @@ loop:
|
|||||||
n = n1
|
n = n1
|
||||||
if i, ok := seen[n]; ok {
|
if i, ok := seen[n]; ok {
|
||||||
// cycle
|
// cycle
|
||||||
check.cycleError(path[i:])
|
check.cycleError(path[i:], firstInSrc(path[i:]))
|
||||||
u = Typ[Invalid]
|
u = Typ[Invalid]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ func (check *Checker) validType0(pos token.Pos, typ Type, nest, path []*Named) b
|
|||||||
// index of t in nest. Search again.
|
// index of t in nest. Search again.
|
||||||
for start, p := range path {
|
for start, p := range path {
|
||||||
if Identical(p, t) {
|
if Identical(p, t) {
|
||||||
check.cycleError(makeObjList(path[start:]))
|
check.cycleError(makeObjList(path[start:]), 0)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ package p
|
|||||||
|
|
||||||
type A[P any] [1]P
|
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
|
// test case from issue
|
||||||
|
|
||||||
@ -17,9 +17,9 @@ type Foo[T any] struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Bar[T any] struct {
|
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]
|
bar Bar[Baz]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user