]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: don't report cycle error if clearer error follows
authorRobert Griesemer <gri@golang.org>
Mon, 17 Sep 2018 20:43:35 +0000 (13:43 -0700)
committerRobert Griesemer <gri@golang.org>
Mon, 17 Sep 2018 23:08:56 +0000 (23:08 +0000)
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>
src/go/types/expr.go
src/go/types/testdata/cycles5.src
src/go/types/testdata/decls0.src
src/go/types/typexpr.go

index c65c9e7681dfe6d92762d3667275377367b02cdc..fc4de98eb774bf5a52114b9f143c20b265d5fe5e 100644 (file)
@@ -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
index 9c2822e738ac13b9ffca4beb66e5be9bdee57112..aa6528a6312e1bdf65e6e44d9598371eae5fa058 100644 (file)
@@ -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
index 162dfeda04e3df471c914292196671845698bdc4..e75216172b83b507001cfdb4368f91ec89c3c216 100644 (file)
@@ -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" */ ) {}
index dab02bc13c9aae6f6477ad352ab01153a5d61b82..12c5c7b0a550308f9bb397e6d06f80b60b4b7106 100644 (file)
@@ -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: