mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00: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.
|
// Each tests entry is list of files belonging to the same package.
|
||||||
var tests = [][]string{
|
var tests = [][]string{
|
||||||
|
{"testdata/cycles.src"},
|
||||||
{"testdata/decls0.src"},
|
{"testdata/decls0.src"},
|
||||||
{"testdata/decls1.src"},
|
{"testdata/decls1.src"},
|
||||||
{"testdata/decls2a.src", "testdata/decls2b.src"},
|
{"testdata/decls2a.src", "testdata/decls2b.src"},
|
||||||
@ -205,7 +206,7 @@ func checkFiles(t *testing.T, testfiles []string) {
|
|||||||
ctxt.Check(pkgName, fset, files...)
|
ctxt.Check(pkgName, fset, files...)
|
||||||
|
|
||||||
if *listErrors {
|
if *listErrors {
|
||||||
t.Errorf("--- %s: %d errors found:", pkgName, len(errlist))
|
t.Errorf("--- %s: %d errors found", pkgName, len(errlist))
|
||||||
for _, err := range errlist {
|
for _, err := range errlist {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -116,13 +116,13 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *checker) collectMethods(list *ast.FieldList) (methods []*Func) {
|
func (check *checker) collectMethods(list *ast.FieldList, cycleOk bool) (methods []*Func) {
|
||||||
if list == nil {
|
if list == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
scope := NewScope(nil)
|
scope := NewScope(nil)
|
||||||
for _, f := range list.List {
|
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
|
// the parser ensures that f.Tag is nil and we don't
|
||||||
// care if a constructed AST contains a non-nil tag
|
// care if a constructed AST contains a non-nil tag
|
||||||
if len(f.Names) > 0 {
|
if len(f.Names) > 0 {
|
||||||
@ -140,18 +140,26 @@ func (check *checker) collectMethods(list *ast.FieldList) (methods []*Func) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// embedded interface
|
// embedded interface
|
||||||
utyp := typ.Underlying()
|
switch t := typ.Underlying().(type) {
|
||||||
if ityp, ok := utyp.(*Interface); ok {
|
case nil:
|
||||||
for _, m := range ityp.methods {
|
// 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)
|
check.declare(scope, nil, m)
|
||||||
methods = append(methods, m)
|
methods = append(methods, m)
|
||||||
}
|
}
|
||||||
} else if utyp != Typ[Invalid] {
|
default:
|
||||||
// if utyp is invalid, don't complain (the root cause was reported before)
|
if t != Typ[Invalid] {
|
||||||
check.errorf(f.Type.Pos(), "%s is not an interface type", typ)
|
check.errorf(f.Type.Pos(), "%s is not an interface type", typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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)
|
check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
|
||||||
x.expr = e
|
x.expr = e
|
||||||
x.typ = Typ[Invalid]
|
x.typ = Typ[Invalid]
|
||||||
return // don't goto Error - need x.mode == typexpr
|
return // don't goto Error - want x.mode == typexpr
|
||||||
}
|
}
|
||||||
case *Var:
|
case *Var:
|
||||||
x.mode = variable
|
x.mode = variable
|
||||||
@ -1494,7 +1502,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||||||
|
|
||||||
case *ast.InterfaceType:
|
case *ast.InterfaceType:
|
||||||
x.mode = typexpr
|
x.mode = typexpr
|
||||||
x.typ = NewInterface(check.collectMethods(e.Methods))
|
x.typ = NewInterface(check.collectMethods(e.Methods, cycleOk))
|
||||||
|
|
||||||
case *ast.MapType:
|
case *ast.MapType:
|
||||||
x.mode = typexpr
|
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…
x
Reference in New Issue
Block a user