mirror of
https://github.com/golang/go
synced 2024-11-18 19:54:44 -07:00
go.tools/go/types: tests for cycles in type decls
Fixed one aspect of issue 5090. Fixing it completely requires a bit more work around the representation of interface types. R=adonovan CC=golang-dev https://golang.org/cl/10678045
This commit is contained in:
parent
b52f745c3a
commit
a0160af20b
@ -45,6 +45,7 @@ var (
|
||||
|
||||
// Each tests entry is list of files belonging to the same package.
|
||||
var tests = [][]string{
|
||||
{"testdata/cycles.src"},
|
||||
{"testdata/decls0.src"},
|
||||
{"testdata/decls1.src"},
|
||||
{"testdata/decls2a.src", "testdata/decls2b.src"},
|
||||
@ -205,7 +206,7 @@ func checkFiles(t *testing.T, testfiles []string) {
|
||||
ctxt.Check(pkgName, fset, files...)
|
||||
|
||||
if *listErrors {
|
||||
t.Errorf("--- %s: %d errors found:", pkgName, len(errlist))
|
||||
t.Errorf("--- %s: %d errors found", pkgName, len(errlist))
|
||||
for _, err := range errlist {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -116,13 +116,13 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
|
||||
return
|
||||
}
|
||||
|
||||
func (check *checker) collectMethods(list *ast.FieldList) (methods []*Func) {
|
||||
func (check *checker) collectMethods(list *ast.FieldList, cycleOk bool) (methods []*Func) {
|
||||
if list == nil {
|
||||
return nil
|
||||
}
|
||||
scope := NewScope(nil)
|
||||
for _, f := range list.List {
|
||||
typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces
|
||||
typ := check.typ(f.Type, cycleOk)
|
||||
// the parser ensures that f.Tag is nil and we don't
|
||||
// care if a constructed AST contains a non-nil tag
|
||||
if len(f.Names) > 0 {
|
||||
@ -140,15 +140,23 @@ func (check *checker) collectMethods(list *ast.FieldList) (methods []*Func) {
|
||||
}
|
||||
} else {
|
||||
// embedded interface
|
||||
utyp := typ.Underlying()
|
||||
if ityp, ok := utyp.(*Interface); ok {
|
||||
for _, m := range ityp.methods {
|
||||
switch t := typ.Underlying().(type) {
|
||||
case nil:
|
||||
// The underlying type is in the process of being defined
|
||||
// but we need it in order to complete this type. For now
|
||||
// complain with an "unimplemented" error. This requires
|
||||
// a bit more work.
|
||||
// TODO(gri) finish this.
|
||||
check.errorf(f.Type.Pos(), "reference to incomplete type %s - unimplemented", f.Type)
|
||||
case *Interface:
|
||||
for _, m := range t.methods {
|
||||
check.declare(scope, nil, m)
|
||||
methods = append(methods, m)
|
||||
}
|
||||
} else if utyp != Typ[Invalid] {
|
||||
// if utyp is invalid, don't complain (the root cause was reported before)
|
||||
check.errorf(f.Type.Pos(), "%s is not an interface type", typ)
|
||||
default:
|
||||
if t != Typ[Invalid] {
|
||||
check.errorf(f.Type.Pos(), "%s is not an interface type", typ)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1042,7 +1050,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
||||
check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
|
||||
x.expr = e
|
||||
x.typ = Typ[Invalid]
|
||||
return // don't goto Error - need x.mode == typexpr
|
||||
return // don't goto Error - want x.mode == typexpr
|
||||
}
|
||||
case *Var:
|
||||
x.mode = variable
|
||||
@ -1494,7 +1502,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
||||
|
||||
case *ast.InterfaceType:
|
||||
x.mode = typexpr
|
||||
x.typ = NewInterface(check.collectMethods(e.Methods))
|
||||
x.typ = NewInterface(check.collectMethods(e.Methods, cycleOk))
|
||||
|
||||
case *ast.MapType:
|
||||
x.mode = typexpr
|
||||
|
112
go/types/testdata/cycles.src
vendored
Normal file
112
go/types/testdata/cycles.src
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright 2013 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 cycles
|
||||
|
||||
type (
|
||||
T0 int
|
||||
T1 /* ERROR "cycle" */ T1
|
||||
T2 *T2
|
||||
|
||||
T3 /* ERROR "cycle" */ T4
|
||||
T4 T5
|
||||
T5 T3
|
||||
|
||||
T6 T7
|
||||
T7 *T8
|
||||
T8 T6
|
||||
|
||||
// arrays
|
||||
A0 /* ERROR "cycle" */ [10]A0
|
||||
A1 [10]*A1
|
||||
|
||||
A2 /* ERROR "cycle" */ [10]A3
|
||||
A3 [10]A4
|
||||
A4 A2
|
||||
|
||||
A5 [10]A6
|
||||
A6 *A5
|
||||
|
||||
// slices
|
||||
L0 []L0
|
||||
|
||||
// structs
|
||||
S0 /* ERROR "cycle" */ struct{ _ S0 }
|
||||
S1 /* ERROR "cycle" */ struct{ S1 }
|
||||
S2 struct{ _ *S2 }
|
||||
S3 struct{ *S3 }
|
||||
|
||||
S4 /* ERROR "cycle" */ struct{ S5 }
|
||||
S5 struct{ S6 }
|
||||
S6 S4
|
||||
|
||||
// pointers
|
||||
P0 *P0
|
||||
|
||||
// functions
|
||||
F0 func(F0)
|
||||
F1 func() F1
|
||||
F2 func(F2) F2
|
||||
|
||||
// interfaces
|
||||
I0 /* ERROR "cycle" */ interface{ I0 }
|
||||
|
||||
I1 /* ERROR "cycle" */ interface{ I2 }
|
||||
I2 interface{ I3 }
|
||||
I3 interface{ I1 }
|
||||
|
||||
I4 interface{ f(I4) }
|
||||
|
||||
// testcase for issue 5090
|
||||
// TODO(gri) fix this
|
||||
I5 interface{ f(I6) }
|
||||
I6 interface{ I5 /* ERROR "unimplemented" */ }
|
||||
|
||||
// maps
|
||||
M0 map[M0]M0
|
||||
|
||||
// channels
|
||||
C0 chan C0
|
||||
)
|
||||
|
||||
func _() {
|
||||
type (
|
||||
t1 /* ERROR "cycle" */ t1
|
||||
t2 *t2
|
||||
|
||||
t3 t4 /* ERROR "undeclared" */
|
||||
t4 t5 /* ERROR "undeclared" */
|
||||
t5 t3
|
||||
|
||||
// arrays
|
||||
a0 /* ERROR "cycle" */ [10]a0
|
||||
a1 [10]*a1
|
||||
|
||||
// slices
|
||||
l0 []l0
|
||||
|
||||
// structs
|
||||
s0 /* ERROR "cycle" */ struct{ _ s0 }
|
||||
s1 /* ERROR "cycle" */ struct{ s1 }
|
||||
s2 struct{ _ *s2 }
|
||||
s3 struct{ *s3 }
|
||||
|
||||
// pointers
|
||||
p0 *p0
|
||||
|
||||
// functions
|
||||
f0 func(f0)
|
||||
f1 func() f1
|
||||
f2 func(f2) f2
|
||||
|
||||
// interfaces
|
||||
i0 /* ERROR "cycle" */ interface{ i0 }
|
||||
|
||||
// maps
|
||||
m0 map[m0]m0
|
||||
|
||||
// channels
|
||||
c0 chan c0
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user