1
0
mirror of https://github.com/golang/go synced 2024-11-18 22:55:23 -07:00

go.tools/go/types: fix type cycle tracking

Fixes golang/go#7236.

LGTM=adonovan
R=adonovan
CC=golang-codereviews
https://golang.org/cl/58430043
This commit is contained in:
Robert Griesemer 2014-01-30 09:46:03 -08:00
parent f97ec06d2c
commit 9cd9226d63
10 changed files with 182 additions and 85 deletions

View File

@ -357,7 +357,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// make(T, n, m)
// (no argument evaluated yet)
arg0 := call.Args[0]
T := check.typ(arg0, nil, false)
T := check.typ(arg0, nil, nil)
if T == Typ[Invalid] {
return
}
@ -395,7 +395,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
case _New:
// new(T)
// (no argument evaluated yet)
T := check.typ(call.Args[0], nil, false)
T := check.typ(call.Args[0], nil, nil)
if T == Typ[Invalid] {
return
}

View File

@ -33,7 +33,7 @@ func (check *checker) declare(scope *Scope, id *ast.Ident, obj Object) {
// objDecl type-checks the declaration of obj in its respective file scope.
// See typeDecl for the details on def and cycleOk.
func (check *checker) objDecl(obj Object, def *Named, cycleOk bool) {
func (check *checker) objDecl(obj Object, def *Named, cycle []*TypeName) {
d := check.objMap[obj]
// adjust file scope for current object
@ -55,7 +55,7 @@ func (check *checker) objDecl(obj Object, def *Named, cycleOk bool) {
check.decl = d // new package-level var decl
check.varDecl(obj, d.lhs, d.typ, d.init)
case *TypeName:
check.typeDecl(obj, d.typ, def, cycleOk)
check.typeDecl(obj, d.typ, def, cycle)
case *Func:
check.funcDecl(obj, d)
default:
@ -68,6 +68,8 @@ func (check *checker) objDecl(obj Object, def *Named, cycleOk bool) {
}
func (check *checker) constDecl(obj *Const, typ, init ast.Expr) {
// TODO(gri) consider using the same cycle detection as for types
// so that we can print the actual cycle in case of an error
if obj.visited {
check.errorf(obj.Pos(), "illegal cycle in initialization of constant %s", obj.name)
obj.typ = Typ[Invalid]
@ -81,7 +83,7 @@ func (check *checker) constDecl(obj *Const, typ, init ast.Expr) {
// determine type, if any
if typ != nil {
t := check.typ(typ, nil, false)
t := check.typ(typ, nil, nil)
if !isConstType(t) {
check.errorf(typ.Pos(), "invalid constant type %s", t)
obj.typ = Typ[Invalid]
@ -103,6 +105,8 @@ func (check *checker) constDecl(obj *Const, typ, init ast.Expr) {
// TODO(gri) document arguments
func (check *checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
// TODO(gri) consider using the same cycle detection as for types
// so that we can print the actual cycle in case of an error
if obj.visited {
check.errorf(obj.Pos(), "illegal cycle in initialization of variable %s", obj.name)
obj.typ = Typ[Invalid]
@ -115,7 +119,7 @@ func (check *checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
// determine type, if any
if typ != nil {
obj.typ = check.typ(typ, nil, false)
obj.typ = check.typ(typ, nil, nil)
}
// check initialization
@ -171,7 +175,7 @@ func (n *Named) setUnderlying(typ Type) {
}
}
func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk bool) {
func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycle []*TypeName) {
assert(obj.Type() == nil)
// type declarations cannot use iota
@ -182,7 +186,7 @@ func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk
obj.typ = named // make sure recursive type declarations terminate
// determine underlying type of named
check.typ(typ, named, cycleOk)
check.typ(typ, named, append(cycle, obj))
// The underlying type of named may be itself a named type that is
// incomplete:
@ -199,9 +203,6 @@ func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk
// any forward chain (they always end in an unnamed type).
named.underlying = underlying(named.underlying)
// the underlying type has been determined
named.complete = true
// type-check signatures of associated methods
methods := check.methods[obj.name]
if len(methods) == 0 {
@ -242,7 +243,7 @@ func (check *checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, cycleOk
}
}
check.recordObject(check.objMap[m].fdecl.Name, m)
check.objDecl(m, nil, true)
check.objDecl(m, nil, nil)
// Methods with blank _ names cannot be found.
// Don't add them to the method list.
if m.name != "_" {
@ -363,7 +364,7 @@ func (check *checker) declStmt(decl ast.Decl) {
case *ast.TypeSpec:
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
check.declare(check.topScope, s.Name, obj)
check.typeDecl(obj, s.Type, nil, false)
check.typeDecl(obj, s.Type, nil, nil)
default:
check.invalidAST(s.Pos(), "const, type, or var declaration expected")

View File

@ -943,7 +943,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, false)
check.ident(x, e, nil, nil)
case *ast.Ellipsis:
// ellipses are handled explicitly where they are legal
@ -959,7 +959,7 @@ func (check *checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}
case *ast.FuncLit:
if sig, ok := check.typ(e.Type, nil, false).(*Signature); ok {
if sig, ok := check.typ(e.Type, nil, nil).(*Signature); ok {
// Anonymous functions are considered part of the
// init expression/func declaration which contains
// them: use existing package-level declaration info.
@ -983,12 +983,12 @@ func (check *checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// We have an "open" [...]T array type.
// Create a new ArrayType with unknown length (-1)
// and finish setting it up after analyzing the literal.
typ = &Array{len: -1, elem: check.typ(atyp.Elt, nil, false)}
typ = &Array{len: -1, elem: check.typ(atyp.Elt, nil, nil)}
openArray = true
}
}
if typ == nil {
typ = check.typ(e.Type, nil, false)
typ = check.typ(e.Type, nil, nil)
}
}
if typ == nil {
@ -1309,7 +1309,7 @@ func (check *checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
check.invalidAST(e.Pos(), "use of .(type) outside type switch")
goto Error
}
T := check.typ(e.Type, nil, false)
T := check.typ(e.Type, nil, nil)
if T == Typ[Invalid] {
goto Error
}
@ -1365,7 +1365,7 @@ func (check *checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
case *ast.ArrayType, *ast.StructType, *ast.FuncType,
*ast.InterfaceType, *ast.MapType, *ast.ChanType:
x.mode = typexpr
x.typ = check.typ(e, nil, false)
x.typ = check.typ(e, nil, nil)
// Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
// even though check.typ has already called it. This is fine as both
// times the same expression and type are recorded. It is also not a

View File

@ -354,13 +354,18 @@ func (check *checker) resolveFiles(files []*ast.File) {
// Phase 3: Typecheck all objects in objMap, but not function bodies.
check.objMap = objMap // indicate that we are checking package-level declarations (objects may not have a type yet)
check.initMap = initMap
check.objMap = objMap // indicate that we are checking package-level declarations (objects may not have a type yet)
emptyCycle := make([]*TypeName, 0, 8) // re-use the same underlying array for cycle detection
for _, obj := range objectsOf(check.objMap) {
if obj.Type() == nil {
check.objDecl(obj, nil, false)
if trace {
check.trace(obj.Pos(), "-- resolving %s", obj.Name())
}
check.objDecl(obj, nil, emptyCycle)
}
}
emptyCycle = nil // not needed anymore
check.objMap = nil // not needed anymore
// At this point we may have a non-empty check.methods map; this means that not all

View File

@ -6,10 +6,10 @@ package cycles
type (
T0 int
T1 /* ERROR "cycle" */ T1
T1 /* ERROR cycle */ T1
T2 *T2
T3 /* ERROR "cycle" */ T4
T3 /* ERROR cycle */ T4
T4 T5
T5 T3
@ -18,10 +18,10 @@ type (
T8 T6
// arrays
A0 /* ERROR "cycle" */ [10]A0
A0 /* ERROR cycle */ [10]A0
A1 [10]*A1
A2 /* ERROR "cycle" */ [10]A3
A2 /* ERROR cycle */ [10]A3
A3 [10]A4
A4 A2
@ -32,12 +32,12 @@ type (
L0 []L0
// structs
S0 /* ERROR "cycle" */ struct{ _ S0 }
S1 /* ERROR "cycle" */ struct{ S1 }
S0 /* ERROR cycle */ struct{ _ S0 }
S1 /* ERROR cycle */ struct{ S1 }
S2 struct{ _ *S2 }
S3 struct{ *S3 }
S4 /* ERROR "cycle" */ struct{ S5 }
S4 /* ERROR cycle */ struct{ S5 }
S5 struct{ S6 }
S6 S4
@ -50,9 +50,9 @@ type (
F2 func(F2) F2
// interfaces
I0 /* ERROR "cycle" */ interface{ I0 }
I0 /* ERROR cycle */ interface{ I0 }
I1 /* ERROR "cycle" */ interface{ I2 }
I1 /* ERROR cycle */ interface{ I2 }
I2 interface{ I3 }
I3 interface{ I1 }
@ -63,7 +63,7 @@ type (
I6 interface{ I5 }
// maps
M0 map[M0 /* ERROR "invalid map key" */ ]M0
M0 map[M0 /* ERROR invalid map key */ ]M0
// channels
C0 chan C0
@ -71,23 +71,23 @@ type (
func _() {
type (
t1 /* ERROR "cycle" */ t1
t1 /* ERROR cycle */ t1
t2 *t2
t3 t4 /* ERROR "undeclared" */
t4 t5 /* ERROR "undeclared" */
t3 t4 /* ERROR undeclared */
t4 t5 /* ERROR undeclared */
t5 t3
// arrays
a0 /* ERROR "cycle" */ [10]a0
a0 /* ERROR cycle */ [10]a0
a1 [10]*a1
// slices
l0 []l0
// structs
s0 /* ERROR "cycle" */ struct{ _ s0 }
s1 /* ERROR "cycle" */ struct{ s1 }
s0 /* ERROR cycle */ struct{ _ s0 }
s1 /* ERROR cycle */ struct{ s1 }
s2 struct{ _ *s2 }
s3 struct{ *s3 }
@ -100,10 +100,10 @@ func _() {
f2 func(f2) f2
// interfaces
i0 /* ERROR "cycle" */ interface{ i0 }
i0 /* ERROR cycle */ interface{ i0 }
// maps
m0 map[m0 /* ERROR "invalid map key" */ ]m0
m0 map[m0 /* ERROR invalid map key */ ]m0
// channels
c0 chan c0
@ -117,3 +117,27 @@ type A [10]map[A /* ERROR invalid map key */ ]bool
type S struct {
m map[S /* ERROR invalid map key */ ]bool
}
// test cases for issue 7236
// (cycle detection must not be dependent on starting point of resolution)
type (
P1 *T9
T9 /* ERROR cycle */ T9
T10 /* ERROR cycle */ T10
P2 *T10
)
func (T11) m() {}
type T11 /* ERROR cycle */ struct{ T11 }
type T12 /* ERROR cycle */ struct{ T12 }
func (*T12) m() {}
type (
P3 *T13
T13 /* ERROR cycle */ T13
)

View File

@ -4,6 +4,8 @@
package p
import "unsafe"
// Test case for issue 5090
type t interface {
@ -61,6 +63,56 @@ var _ = x /* ERROR cannot compare */ == y
// Test case for issue 6638.
type T /* ERROR cycle */ interface {
m() [T /* ERROR no field or method */ (nil).m()[0]]int
type T interface {
m() [T /* ERROR no value */ (nil).m()[0]]int
}
// Variations of this test case.
type T1 interface {
m() [x1 /* ERROR no value */ .m()[0]]int
}
var x1 T1
type T2 interface {
m() [len(x2 /* ERROR no value */ .m())]int
}
var x2 T2
type T3 interface {
m() [unsafe.Sizeof(x3.m)]int
}
var x3 T3
// The test case below should also report an error for
// the cast inside the T4 interface (like it does for the
// variable initialization). The reason why it does not is
// that inside T4, the method x4.m depends on T4 which is not
// fully set up yet. The x4.m method happens to have an empty
// signature which is why the cast is permitted.
// TODO(gri) Consider marking methods as incomplete and provide
// a better error message in that case.
type T4 interface {
m() [unsafe.Sizeof(cast4(x4.m))]int
}
var x4 T4
var _ = cast4(x4 /* ERROR cannot convert */.m)
type cast4 func()
// This test is symmetric to the T4 case: Here the cast is
// "correct", but it doesn't work inside the T5 interface.
type T5 interface {
m() [unsafe.Sizeof(cast5(x5 /* ERROR cannot convert */ .m))]int
}
var x5 T5
var _ = cast5(x5.m)
type cast5 func() [0]int

View File

@ -48,7 +48,7 @@ type (
)
type (
U /* ERROR illegal cycle */ interface {
U interface {
V
}

View File

@ -365,8 +365,7 @@ func (c *Chan) Elem() Type { return c.elem }
// A Named represents a named type.
type Named struct {
obj *TypeName // corresponding declared object
underlying Type // possibly a *Named if !complete; never a *Named if complete
complete bool // if set, the underlying type has been determined
underlying Type // possibly a *Named during setup; never a *Named once set up completely
methods []*Func // methods declared for this type (not the method set of this type)
mset, pmset cachedMethodSet // method set for T, *T, lazily initialized
}
@ -377,7 +376,7 @@ func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
if _, ok := underlying.(*Named); ok {
panic("types.NewNamed: underlying type must not be *Named")
}
typ := &Named{obj: obj, underlying: underlying, complete: underlying != nil, methods: methods}
typ := &Named{obj: obj, underlying: underlying, methods: methods}
if obj.typ == nil {
obj.typ = typ
}
@ -403,7 +402,6 @@ func (t *Named) SetUnderlying(underlying Type) {
panic("types.Named.SetUnderlying: underlying type must not be *Named")
}
t.underlying = underlying
t.complete = true
}
// AddMethod adds method m unless it is already in the method list.

View File

@ -17,9 +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 and cycleOk, see check.typ, below.
// For the meaning of def and cycle, see check.typ, below.
//
func (check *checker) ident(x *operand, e *ast.Ident, def *Named, cycleOk bool) {
func (check *checker) ident(x *operand, e *ast.Ident, def *Named, cycle []*TypeName) {
x.mode = invalid
x.expr = e
@ -41,7 +41,7 @@ func (check *checker) ident(x *operand, e *ast.Ident, def *Named, cycleOk bool)
check.dump("%s: %s should have been declared (we are inside a function)", e.Pos(), e)
unreachable()
}
check.objDecl(obj, def, cycleOk)
check.objDecl(obj, def, cycle)
typ = obj.Type()
}
assert(typ != nil)
@ -76,11 +76,16 @@ func (check *checker) ident(x *operand, e *ast.Ident, def *Named, cycleOk bool)
case *TypeName:
obj.used = true
x.mode = typexpr
named, _ := typ.(*Named)
if !cycleOk && named != nil && !named.complete {
check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
// maintain x.mode == typexpr despite error
typ = Typ[Invalid]
// check for cycle
// TODO(gri) consider passing []*Named instead of []*TypeName for cycle
for _, prev := range cycle {
if prev == obj {
check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
// TODO(gri) print the actual cycle
// maintain x.mode == typexpr despite error
typ = Typ[Invalid]
break
}
}
case *Var:
@ -117,10 +122,10 @@ func (check *checker) ident(x *operand, e *ast.Ident, def *Named, cycleOk bool)
// If def != nil, e is the type specification for the named type def, declared
// in a type declaration, and def.underlying will be set to the type of e before
// any components of e are type-checked.
// If cycleOk is set, e (or elements of e) may refer to a named type that is not
// If cycle is not empty, e (or elements of e) may refer to a named type that is not
// yet completely set up.
//
func (check *checker) typ(e ast.Expr, def *Named, cycleOk bool) (T Type) {
func (check *checker) typ(e ast.Expr, def *Named, cycle []*TypeName) (T Type) {
if trace {
check.trace(e.Pos(), "%s", e)
check.indent++
@ -130,13 +135,16 @@ func (check *checker) typ(e ast.Expr, def *Named, cycleOk bool) (T Type) {
}()
}
T = check.typInternal(e, def, cycleOk)
T = check.typInternal(e, def, cycle)
assert(isTyped(T))
check.recordTypeAndValue(e, T, nil)
return
}
// TODO(gri) provide a convenience function (say, check.typExpr) that works
// as check.typ but only takes an ast.Expr and assumes nil for def and cycle.
// funcType type-checks a function or method type and returns its signature.
func (check *checker) funcType(sig *Signature, recv *ast.FieldList, ftyp *ast.FuncType) *Signature {
scope := NewScope(check.topScope)
@ -197,14 +205,14 @@ func (check *checker) funcType(sig *Signature, recv *ast.FieldList, ftyp *ast.Fu
// typInternal drives type checking of types.
// Must only be called by typ.
//
func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
func (check *checker) typInternal(e ast.Expr, def *Named, cycle []*TypeName) Type {
switch e := e.(type) {
case *ast.BadExpr:
// ignore - error reported before
case *ast.Ident:
var x operand
check.ident(&x, e, def, cycleOk)
check.ident(&x, e, def, cycle)
switch x.mode {
case typexpr:
@ -237,33 +245,33 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
}
case *ast.ParenExpr:
return check.typ(e.X, def, cycleOk)
return check.typ(e.X, def, cycle)
case *ast.ArrayType:
if e.Len != nil {
typ := new(Array)
def.setUnderlying(typ)
typ.len = check.arrayLength(e.Len)
typ.elem = check.typ(e.Elt, nil, cycleOk)
typ.elem = check.typ(e.Elt, nil, cycle)
return typ
} else {
typ := new(Slice)
def.setUnderlying(typ)
typ.elem = check.typ(e.Elt, nil, true)
typ.elem = check.typ(e.Elt, nil, nil)
return typ
}
case *ast.StructType:
typ := new(Struct)
def.setUnderlying(typ)
check.structType(typ, e, cycleOk)
check.structType(typ, e, cycle)
return typ
case *ast.StarExpr:
typ := new(Pointer)
def.setUnderlying(typ)
typ.base = check.typ(e.X, nil, true)
typ.base = check.typ(e.X, nil, nil)
return typ
case *ast.FuncType:
@ -275,15 +283,15 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
case *ast.InterfaceType:
typ := new(Interface)
def.setUnderlying(typ)
check.interfaceType(typ, e, def, cycleOk)
check.interfaceType(typ, e, def, cycle)
return typ
case *ast.MapType:
typ := new(Map)
def.setUnderlying(typ)
typ.key = check.typ(e.Key, nil, true)
typ.elem = check.typ(e.Value, nil, true)
typ.key = check.typ(e.Key, nil, nil)
typ.elem = check.typ(e.Value, nil, nil)
// spec: "The comparison operators == and != must be fully defined
// for operands of the key type; thus the key type must not be a
@ -317,7 +325,7 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
}
typ.dir = dir
typ.elem = check.typ(e.Value, nil, true)
typ.elem = check.typ(e.Value, nil, nil)
return typ
default:
@ -391,7 +399,7 @@ func (check *checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
// ignore ... and continue
}
}
typ := check.typ(ftype, nil, true)
typ := check.typ(ftype, nil, nil)
// The parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag.
if len(field.Names) > 0 {
@ -427,7 +435,7 @@ func (check *checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool
return true
}
func (check *checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, def *Named, cycleOk bool) {
func (check *checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, def *Named, cycle []*TypeName) {
// empty interface: common case
if ityp.Methods == nil {
return
@ -436,6 +444,12 @@ func (check *checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, d
// The parser ensures that field tags are nil and we don't
// care if a constructed AST contains non-nil tags.
// use named receiver type if available (for better error messages)
var recvTyp Type = iface
if def != nil {
recvTyp = def
}
// Phase 1: Collect explicitly declared methods, the corresponding
// signature (AST) expressions, and the list of embedded
// type (AST) expressions. Do not resolve signatures or
@ -455,7 +469,15 @@ func (check *checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, d
pos := name.Pos()
// Don't type-check signature yet - use an
// empty signature now and update it later.
m := NewFunc(pos, check.pkg, name.Name, new(Signature))
// Since we know the receiver, set it up now
// (required to avoid crash in ptrRecv; see
// e.g. test case for issue 6638).
// TODO(gri) Consider marking methods signatures
// as incomplete, for better error messages. See
// also the T4 and T5 tests in testdata/cycles2.src.
sig := new(Signature)
sig.recv = NewVar(pos, check.pkg, "", recvTyp)
m := NewFunc(pos, check.pkg, name.Name, sig)
// spec: "As with all method sets, in an interface type,
// each method must have a unique name."
// (The spec does not exclude blank _ identifiers for
@ -484,7 +506,7 @@ func (check *checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, d
for _, e := range embedded {
pos := e.Pos()
typ := check.typ(e, nil, cycleOk)
typ := check.typ(e, nil, cycle)
named, _ := typ.(*Named)
if named == nil {
if typ != Typ[Invalid] {
@ -517,16 +539,9 @@ func (check *checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, d
// and embed the methods of this interface in a parameter of interface
// type.
// determine receiver type
var recv Type = iface
if def != nil {
def.underlying = iface
recv = def // use named receiver type if available
}
for i, m := range iface.methods {
expr := signatures[i]
typ := check.typ(expr, nil, true)
typ := check.typ(expr, nil, nil)
sig, _ := typ.(*Signature)
if sig == nil {
if typ != Typ[Invalid] {
@ -534,8 +549,10 @@ func (check *checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, d
}
continue // keep method with empty method signature
}
sig.recv = NewVar(m.pos, check.pkg, "", recv)
*m.typ.(*Signature) = *sig // update signature (don't replace it!)
// update signature, but keep recv that was set up before
old := m.typ.(*Signature)
sig.recv = old.recv
*old = *sig // update signature (don't replace it!)
}
// TODO(gri) The list of explicit methods is only sorted for now to
@ -577,7 +594,7 @@ func (check *checker) tag(t *ast.BasicLit) string {
return ""
}
func (check *checker) structType(styp *Struct, e *ast.StructType, cycleOk bool) {
func (check *checker) structType(styp *Struct, e *ast.StructType, cycle []*TypeName) {
list := e.Fields
if list == nil {
return
@ -612,7 +629,7 @@ func (check *checker) structType(styp *Struct, e *ast.StructType, cycleOk bool)
}
for _, f := range list.List {
typ = check.typ(f.Type, nil, cycleOk)
typ = check.typ(f.Type, nil, cycle)
tag = check.tag(f.Tag)
if len(f.Names) > 0 {
// named fields

View File

@ -69,7 +69,7 @@ func defPredeclaredTypes() {
res := NewVar(token.NoPos, nil, "", Typ[String])
sig := &Signature{results: NewTuple(res)}
err := NewFunc(token.NoPos, nil, "Error", sig)
typ := &Named{underlying: NewInterface([]*Func{err}, nil), complete: true}
typ := &Named{underlying: NewInterface([]*Func{err}, nil)}
sig.recv = NewVar(token.NoPos, nil, "", typ)
def(NewTypeName(token.NoPos, nil, "error", typ))
}