Commit d97b11f1 authored by Robert Griesemer's avatar Robert Griesemer

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/135700Reviewed-by: 's avatarAlan Donovan <adonovan@google.com>
parent 36531204
......@@ -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
......
......@@ -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
......@@ -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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment