mirror of
https://github.com/golang/go
synced 2024-11-23 18:50:05 -07:00
go/types: don't report cycle error if clearer error follows
If a cyclic declaration uses a non-type object where it expects a type, don't report the cycle error in favor of the clearer and more informative error about the missing type. Fixes #25790. Change-Id: If937078383def878efb4c69686e5b4b2a495fd5d Reviewed-on: https://go-review.googlesource.com/135700 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
36531204f4
commit
d97b11f12f
@ -1010,7 +1010,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
||||
goto Error // error was reported before
|
||||
|
||||
case *ast.Ident:
|
||||
check.ident(x, e, nil)
|
||||
check.ident(x, e, nil, false)
|
||||
|
||||
case *ast.Ellipsis:
|
||||
// ellipses are handled explicitly where they are legal
|
||||
|
21
src/go/types/testdata/cycles5.src
vendored
21
src/go/types/testdata/cycles5.src
vendored
@ -162,20 +162,29 @@ func makeArray() (res T12) { return }
|
||||
var r /* ERROR cycle */ = newReader()
|
||||
func newReader() r
|
||||
|
||||
// variations of the theme of #8699 amd #20770
|
||||
// variations of the theme of #8699 and #20770
|
||||
var arr /* ERROR cycle */ = f()
|
||||
func f() [len(arr)]int
|
||||
|
||||
// TODO(gri) here we should only get one error
|
||||
func ff /* ERROR cycle */ (ff /* ERROR not a type */ )
|
||||
// issue #25790
|
||||
func ff(ff /* ERROR not a type */ )
|
||||
func gg((gg /* ERROR not a type */ ))
|
||||
|
||||
type T13 /* ERROR cycle */ [len(b13)]int
|
||||
var b13 T13
|
||||
|
||||
func g /* ERROR cycle */ () [unsafe.Sizeof(x)]int
|
||||
var x = g
|
||||
func g1() [unsafe.Sizeof(g1)]int
|
||||
func g2() [unsafe.Sizeof(x2)]int
|
||||
var x2 = g2
|
||||
|
||||
func h /* ERROR cycle */ () [h /* ERROR no value */ ()[0]]int { panic(0) }
|
||||
// verify that we get the correct sizes for the functions above
|
||||
// (note: assert is statically evaluated in go/types test mode)
|
||||
func init() {
|
||||
assert(unsafe.Sizeof(g1) == 8)
|
||||
assert(unsafe.Sizeof(x2) == 8)
|
||||
}
|
||||
|
||||
func h() [h /* ERROR no value */ ()[0]]int { panic(0) }
|
||||
|
||||
var c14 /* ERROR cycle */ T14
|
||||
type T14 [uintptr(unsafe.Sizeof(&c14))]byte
|
||||
|
10
src/go/types/testdata/decls0.src
vendored
10
src/go/types/testdata/decls0.src
vendored
@ -183,11 +183,11 @@ type (
|
||||
)
|
||||
|
||||
// cycles in function/method declarations
|
||||
// (test cases for issue 5217 and variants)
|
||||
func f1 /* ERROR cycle */ (x f1 /* ERROR "not a type" */ ) {}
|
||||
func f2 /* ERROR cycle */ (x *f2 /* ERROR "not a type" */ ) {}
|
||||
func f3 /* ERROR cycle */ () (x f3 /* ERROR "not a type" */ ) { return }
|
||||
func f4 /* ERROR cycle */ () (x *f4 /* ERROR "not a type" */ ) { return }
|
||||
// (test cases for issues #5217, #25790 and variants)
|
||||
func f1(x f1 /* ERROR "not a type" */ ) {}
|
||||
func f2(x *f2 /* ERROR "not a type" */ ) {}
|
||||
func f3() (x f3 /* ERROR "not a type" */ ) { return }
|
||||
func f4() (x *f4 /* ERROR "not a type" */ ) { return }
|
||||
|
||||
func (S0) m1(x S0.m1 /* ERROR "field or method" */ ) {}
|
||||
func (S0) m2(x *S0.m2 /* ERROR "field or method" */ ) {}
|
||||
|
@ -17,8 +17,9 @@ import (
|
||||
// ident type-checks identifier e and initializes x with the value or type of e.
|
||||
// If an error occurred, x.mode is set to invalid.
|
||||
// For the meaning of def, see Checker.definedType, below.
|
||||
// If wantType is set, the identifier e is expected to denote a type.
|
||||
//
|
||||
func (check *Checker) ident(x *operand, e *ast.Ident, def *Named) {
|
||||
func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) {
|
||||
x.mode = invalid
|
||||
x.expr = e
|
||||
|
||||
@ -35,8 +36,19 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named) {
|
||||
}
|
||||
check.recordUse(e, obj)
|
||||
|
||||
check.objDecl(obj, def)
|
||||
// Type-check the object.
|
||||
// Only call Checker.objDecl if the object doesn't have a type yet
|
||||
// (in which case we must actually determine it) or the object is a
|
||||
// TypeName and we also want a type (in which case we might detect
|
||||
// a cycle which needs to be reported). Otherwise we can skip the
|
||||
// call and avoid a possible cycle error in favor of the more
|
||||
// informative "not a type/value" error that this function's caller
|
||||
// will issue (see issue #25790).
|
||||
typ := obj.Type()
|
||||
if _, gotType := obj.(*TypeName); typ == nil || gotType && wantType {
|
||||
check.objDecl(obj, def)
|
||||
typ = obj.Type() // type must have been assigned by Checker.objDecl
|
||||
}
|
||||
assert(typ != nil)
|
||||
|
||||
// The object may be dot-imported: If so, remove its package from
|
||||
@ -215,7 +227,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
|
||||
|
||||
case *ast.Ident:
|
||||
var x operand
|
||||
check.ident(&x, e, def)
|
||||
check.ident(&x, e, def, true)
|
||||
|
||||
switch x.mode {
|
||||
case typexpr:
|
||||
|
Loading…
Reference in New Issue
Block a user