mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
go/types, types2: print qualified object names in cycle errors
Fixes #50788. Change-Id: Id1ed7d9c0687e3005e28598373fd5634178c78ca Reviewed-on: https://go-review.googlesource.com/c/go/+/413895 Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
3e58ef6cc7
commit
73475ef035
5 changed files with 61 additions and 8 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
package types2
|
package types2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"cmd/compile/internal/syntax"
|
"cmd/compile/internal/syntax"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
|
|
@ -303,11 +304,23 @@ loop:
|
||||||
// cycleError reports a declaration cycle starting with
|
// cycleError reports a declaration cycle starting with
|
||||||
// the object in cycle that is "first" in the source.
|
// the object in cycle that is "first" in the source.
|
||||||
func (check *Checker) cycleError(cycle []Object) {
|
func (check *Checker) cycleError(cycle []Object) {
|
||||||
|
// name returns the (possibly qualified) object name.
|
||||||
|
// This is needed because with generic types, cycles
|
||||||
|
// may refer to imported types. See issue #50788.
|
||||||
|
// TODO(gri) Thus functionality is used elsewhere. Factor it out.
|
||||||
|
name := func(obj Object) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
writePackage(&buf, obj.Pkg(), check.qualifier)
|
||||||
|
buf.WriteString(obj.Name())
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(gri) Should we start with the last (rather than the first) object in the cycle
|
// 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
|
// since that is the earliest point in the source where we start seeing the
|
||||||
// cycle? That would be more consistent with other error messages.
|
// cycle? That would be more consistent with other error messages.
|
||||||
i := firstInSrc(cycle)
|
i := firstInSrc(cycle)
|
||||||
obj := cycle[i]
|
obj := cycle[i]
|
||||||
|
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)
|
||||||
if tname != nil && tname.IsAlias() {
|
if tname != nil && tname.IsAlias() {
|
||||||
|
|
@ -315,19 +328,20 @@ func (check *Checker) cycleError(cycle []Object) {
|
||||||
}
|
}
|
||||||
var err error_
|
var err error_
|
||||||
if tname != nil && check.conf.CompilerErrorMessages {
|
if tname != nil && check.conf.CompilerErrorMessages {
|
||||||
err.errorf(obj, "invalid recursive type %s", obj.Name())
|
err.errorf(obj, "invalid recursive type %s", objName)
|
||||||
} else {
|
} else {
|
||||||
err.errorf(obj, "illegal cycle in declaration of %s", obj.Name())
|
err.errorf(obj, "illegal cycle in declaration of %s", objName)
|
||||||
}
|
}
|
||||||
for range cycle {
|
for range cycle {
|
||||||
err.errorf(obj, "%s refers to", obj.Name())
|
err.errorf(obj, "%s refers to", objName)
|
||||||
i++
|
i++
|
||||||
if i >= len(cycle) {
|
if i >= len(cycle) {
|
||||||
i = 0
|
i = 0
|
||||||
}
|
}
|
||||||
obj = cycle[i]
|
obj = cycle[i]
|
||||||
|
objName = name(obj)
|
||||||
}
|
}
|
||||||
err.errorf(obj, "%s", obj.Name())
|
err.errorf(obj, "%s", objName)
|
||||||
check.report(&err)
|
check.report(&err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/constant"
|
"go/constant"
|
||||||
|
|
@ -302,30 +303,43 @@ loop:
|
||||||
// cycleError reports a declaration cycle starting with
|
// cycleError reports a declaration cycle starting with
|
||||||
// the object in cycle that is "first" in the source.
|
// the object in cycle that is "first" in the source.
|
||||||
func (check *Checker) cycleError(cycle []Object) {
|
func (check *Checker) cycleError(cycle []Object) {
|
||||||
|
// name returns the (possibly qualified) object name.
|
||||||
|
// This is needed because with generic types, cycles
|
||||||
|
// may refer to imported types. See issue #50788.
|
||||||
|
// TODO(gri) Thus functionality is used elsewhere. Factor it out.
|
||||||
|
name := func(obj Object) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
writePackage(&buf, obj.Pkg(), check.qualifier)
|
||||||
|
buf.WriteString(obj.Name())
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(gri) Should we start with the last (rather than the first) object in the cycle
|
// 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
|
// since that is the earliest point in the source where we start seeing the
|
||||||
// cycle? That would be more consistent with other error messages.
|
// cycle? That would be more consistent with other error messages.
|
||||||
i := firstInSrc(cycle)
|
i := firstInSrc(cycle)
|
||||||
obj := cycle[i]
|
obj := cycle[i]
|
||||||
|
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)
|
||||||
if tname != nil && tname.IsAlias() {
|
if tname != nil && tname.IsAlias() {
|
||||||
check.validAlias(tname, Typ[Invalid])
|
check.validAlias(tname, Typ[Invalid])
|
||||||
}
|
}
|
||||||
if tname != nil && compilerErrorMessages {
|
if tname != nil && compilerErrorMessages {
|
||||||
check.errorf(obj, _InvalidDeclCycle, "invalid recursive type %s", obj.Name())
|
check.errorf(obj, _InvalidDeclCycle, "invalid recursive type %s", objName)
|
||||||
} else {
|
} else {
|
||||||
check.errorf(obj, _InvalidDeclCycle, "illegal cycle in declaration of %s", obj.Name())
|
check.errorf(obj, _InvalidDeclCycle, "illegal cycle in declaration of %s", objName)
|
||||||
}
|
}
|
||||||
for range cycle {
|
for range cycle {
|
||||||
check.errorf(obj, _InvalidDeclCycle, "\t%s refers to", obj.Name()) // secondary error, \t indented
|
check.errorf(obj, _InvalidDeclCycle, "\t%s refers to", objName) // secondary error, \t indented
|
||||||
i++
|
i++
|
||||||
if i >= len(cycle) {
|
if i >= len(cycle) {
|
||||||
i = 0
|
i = 0
|
||||||
}
|
}
|
||||||
obj = cycle[i]
|
obj = cycle[i]
|
||||||
|
objName = name(obj)
|
||||||
}
|
}
|
||||||
check.errorf(obj, _InvalidDeclCycle, "\t%s", obj.Name())
|
check.errorf(obj, _InvalidDeclCycle, "\t%s", objName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// firstInSrc reports the index of the object with the "smallest"
|
// firstInSrc reports the index of the object with the "smallest"
|
||||||
|
|
|
||||||
9
test/fixedbugs/issue50788.dir/a.go
Normal file
9
test/fixedbugs/issue50788.dir/a.go
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright 2022 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 a
|
||||||
|
|
||||||
|
type T[P any] struct {
|
||||||
|
_ P
|
||||||
|
}
|
||||||
9
test/fixedbugs/issue50788.dir/b.go
Normal file
9
test/fixedbugs/issue50788.dir/b.go
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright 2022 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 b
|
||||||
|
|
||||||
|
import "./a"
|
||||||
|
|
||||||
|
type T a.T[T] // ERROR "invalid recursive type T\n.*T refers to\n.*a\.T refers to\n.*T"
|
||||||
7
test/fixedbugs/issue50788.go
Normal file
7
test/fixedbugs/issue50788.go
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
// errorcheckdir
|
||||||
|
|
||||||
|
// Copyright 2022 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 ignored
|
||||||
Loading…
Add table
Add a link
Reference in a new issue