{pkgpath: "aliases", name: "C0", want: "type C0 struct{f1 C1; f2 C1}"},
{pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"},
{pkgpath: "issue27856", name: "M", want: "type M struct{E F}"},
+ {pkgpath: "v1reflect", name: "Type", want: "type Type interface{Align() int; AssignableTo(u Type) bool; Bits() int; ChanDir() ChanDir; Elem() Type; Field(i int) StructField; FieldAlign() int; FieldByIndex(index []int) StructField; FieldByName(name string) (StructField, bool); FieldByNameFunc(match func(string) bool) (StructField, bool); Implements(u Type) bool; In(i int) Type; IsVariadic() bool; Key() Type; Kind() Kind; Len() int; Method(int) Method; MethodByName(string) (Method, bool); Name() string; NumField() int; NumIn() int; NumMethod() int; NumOut() int; Out(i int) Type; PkgPath() string; Size() uintptr; String() string; common() *commonType; rawString() string; runtimeType() *runtimeType; uncommon() *uncommonType}"},
}
func TestGoxImporter(t *testing.T) {
imports map[string]*types.Package // package path -> package object
typeList []types.Type // type number -> type
typeData []string // unparsed type data (v3 and later)
+ fixups []fixupRecord // fixups to apply at end of parsing
initdata InitData // package init priority data
}
+// When reading V1 export data it's possible to encounter a defined
+// type N1 with an underlying defined type N2 while we are still
+// reading in that defined type N2; see issue #29006 for an instance
+// of this. Example:
+//
+// type N1 N2
+// type N2 struct {
+// ...
+// p *N1
+// }
+//
+// To handle such cases, the parser generates a fixup record (below) and
+// delays setting of N1's underlying type until parsing is complete, at
+// which point fixups are applied.
+
+type fixupRecord struct {
+ toUpdate *types.Named // type to modify when fixup is processed
+ target types.Type // type that was incomplete when fixup was created
+}
+
func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) {
p.scanner = new(scanner.Scanner)
p.initScanner(filename, src)
underlying := p.parseType(pkg)
if nt.Underlying() == nil {
- nt.SetUnderlying(underlying.Underlying())
+ if underlying.Underlying() == nil {
+ if p.version != "v1" {
+ p.errorf("internal error: unexpected fixup required for %v", nt)
+ }
+ fix := fixupRecord{toUpdate: nt, target: underlying}
+ p.fixups = append(p.fixups, fix)
+ } else {
+ nt.SetUnderlying(underlying.Underlying())
+ }
}
if p.tok == '\n' {
for p.tok != scanner.EOF {
p.parseDirective()
}
+ for _, f := range p.fixups {
+ if f.target.Underlying() == nil {
+ p.errorf("internal error: fixup can't be applied, loop required")
+ }
+ f.toUpdate.SetUnderlying(f.target.Underlying())
+ }
+ p.fixups = nil
for _, typ := range p.typeList {
if it, ok := typ.(*types.Interface); ok {
it.Complete()