From: Robert Griesemer Date: Mon, 17 Sep 2018 20:43:35 +0000 (-0700) Subject: go/types: don't report cycle error if clearer error follows X-Git-Tag: go1.12beta1~1067 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=d97b11f12fb36ae8117519ee983a8f811360ee1a;p=gostls13.git 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 --- diff --git a/src/go/types/expr.go b/src/go/types/expr.go index c65c9e7681..fc4de98eb7 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -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 diff --git a/src/go/types/testdata/cycles5.src b/src/go/types/testdata/cycles5.src index 9c2822e738..aa6528a631 100644 --- a/src/go/types/testdata/cycles5.src +++ b/src/go/types/testdata/cycles5.src @@ -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 diff --git a/src/go/types/testdata/decls0.src b/src/go/types/testdata/decls0.src index 162dfeda04..e75216172b 100644 --- a/src/go/types/testdata/decls0.src +++ b/src/go/types/testdata/decls0.src @@ -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" */ ) {} diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index dab02bc13c..12c5c7b0a5 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -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: