mirror of
https://github.com/golang/go
synced 2024-09-04 23:44:16 +00:00
cmd/compile/internal/gc: export interface embedding information
Fixes #16369. Change-Id: I23f8c36370d0da37ac5b5126d012d22f78782782 Reviewed-on: https://go-review.googlesource.com/38392 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
07de3465be
commit
ee272bbf36
|
@ -753,39 +753,7 @@ func (p *exporter) typ(t *Type) {
|
|||
|
||||
case TINTER:
|
||||
p.tag(interfaceTag)
|
||||
// gc doesn't separate between embedded interfaces
|
||||
// and methods declared explicitly with an interface
|
||||
p.int(0) // no embedded interfaces
|
||||
|
||||
// Because the compiler flattens interfaces containing
|
||||
// embedded interfaces, it is possible to create interface
|
||||
// types that recur through an unnamed type.
|
||||
// If trackAllTypes is disabled, such recursion is not
|
||||
// detected, leading to a stack overflow during export
|
||||
// (issue #16369).
|
||||
// As a crude work-around we terminate deep recursion
|
||||
// through interface types with an empty interface and
|
||||
// report an error.
|
||||
// This will catch endless recursion, but is unlikely
|
||||
// to trigger for valid, deeply nested types given the
|
||||
// high threshold.
|
||||
// It would be ok to continue without reporting an error
|
||||
// since the export format is valid. But a subsequent
|
||||
// import would import an incorrect type. The textual
|
||||
// exporter does not report an error but importing the
|
||||
// resulting package will lead to a syntax error during
|
||||
// import.
|
||||
// TODO(gri) remove this once we have a permanent fix
|
||||
// for the issue.
|
||||
if p.nesting > 100 {
|
||||
p.int(0) // 0 methods to indicate empty interface
|
||||
yyerrorl(t.Pos, "cannot export unnamed recursive interface")
|
||||
break
|
||||
}
|
||||
|
||||
p.nesting++
|
||||
p.methodList(t)
|
||||
p.nesting--
|
||||
|
||||
case TMAP:
|
||||
p.tag(mapTag)
|
||||
|
@ -830,18 +798,44 @@ func (p *exporter) field(f *Field) {
|
|||
}
|
||||
|
||||
func (p *exporter) methodList(t *Type) {
|
||||
if p.trace && t.NumFields() > 0 {
|
||||
p.tracef("methods {>")
|
||||
defer p.tracef("<\n} ")
|
||||
var embeddeds, methods []*Field
|
||||
|
||||
for _, m := range t.Methods().Slice() {
|
||||
if m.Sym != nil {
|
||||
methods = append(methods, m)
|
||||
} else {
|
||||
embeddeds = append(embeddeds, m)
|
||||
}
|
||||
}
|
||||
|
||||
p.int(t.NumFields())
|
||||
for _, m := range t.Fields().Slice() {
|
||||
if p.trace && len(embeddeds) > 0 {
|
||||
p.tracef("embeddeds {>")
|
||||
}
|
||||
p.int(len(embeddeds))
|
||||
for _, m := range embeddeds {
|
||||
if p.trace {
|
||||
p.tracef("\n")
|
||||
}
|
||||
p.pos(m.Nname)
|
||||
p.typ(m.Type)
|
||||
}
|
||||
if p.trace && len(embeddeds) > 0 {
|
||||
p.tracef("<\n} ")
|
||||
}
|
||||
|
||||
if p.trace && len(methods) > 0 {
|
||||
p.tracef("methods {>")
|
||||
}
|
||||
p.int(len(methods))
|
||||
for _, m := range methods {
|
||||
if p.trace {
|
||||
p.tracef("\n")
|
||||
}
|
||||
p.method(m)
|
||||
}
|
||||
if p.trace && len(methods) > 0 {
|
||||
p.tracef("<\n} ")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *exporter) method(m *Field) {
|
||||
|
|
|
@ -526,9 +526,6 @@ func (p *importer) typ() *Type {
|
|||
functypefield0(t, nil, params, result)
|
||||
|
||||
case interfaceTag:
|
||||
if p.int() != 0 {
|
||||
formatErrorf("unexpected embedded interface")
|
||||
}
|
||||
if ml := p.methodList(); len(ml) == 0 {
|
||||
t = Types[TINTER]
|
||||
} else {
|
||||
|
@ -604,12 +601,18 @@ func (p *importer) field() *Field {
|
|||
}
|
||||
|
||||
func (p *importer) methodList() (methods []*Field) {
|
||||
if n := p.int(); n > 0 {
|
||||
methods = make([]*Field, n)
|
||||
for i := range methods {
|
||||
methods[i] = p.method()
|
||||
}
|
||||
for n := p.int(); n > 0; n-- {
|
||||
f := newField()
|
||||
f.Nname = newname(nblank.Sym)
|
||||
f.Nname.Pos = p.pos()
|
||||
f.Type = p.typ()
|
||||
methods = append(methods, f)
|
||||
}
|
||||
|
||||
for n := p.int(); n > 0; n-- {
|
||||
methods = append(methods, p.method())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -492,12 +492,13 @@ func (p *importer) typ(parent *types.Package) types.Type {
|
|||
p.record(nil)
|
||||
}
|
||||
|
||||
// no embedded interfaces with gc compiler
|
||||
if p.int() != 0 {
|
||||
errorf("unexpected embedded interface")
|
||||
var embeddeds []*types.Named
|
||||
for n := p.int(); n > 0; n-- {
|
||||
p.pos()
|
||||
embeddeds = append(embeddeds, p.typ(parent).(*types.Named))
|
||||
}
|
||||
|
||||
t := types.NewInterface(p.methodList(parent), nil)
|
||||
t := types.NewInterface(p.methodList(parent), embeddeds)
|
||||
if p.trackAllTypes {
|
||||
p.typList[n] = t
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ var importedObjectTests = []struct {
|
|||
}{
|
||||
{"math.Pi", "const Pi untyped float"},
|
||||
{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
|
||||
{"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
|
||||
{"io.ReadWriter", "type ReadWriter interface{Reader; Writer}"},
|
||||
{"math.Sin", "func Sin(x float64) float64"},
|
||||
// TODO(gri) add more tests
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// errorcheck
|
||||
// compile
|
||||
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
|
@ -7,7 +7,7 @@
|
|||
package p
|
||||
|
||||
type T interface {
|
||||
M(interface { // ERROR "cannot export unnamed recursive interface"
|
||||
M(interface {
|
||||
T
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue