go/internal/gccgoimporter: port recent changes from stdlib version

This CL brings over the following changes from the std lib:

	https://golang.org/cl/137857
	https://golang.org/cl/137935
	https://golang.org/cl/137975

There are no further code changes except that the importer test
cases are split between importer_test.go and importer19_test.go
to support multiple Go versions.

Updates golang/go#27856.

Change-Id: I625def738c22c24c6659af37c3871038fdd8b981
Reviewed-on: https://go-review.googlesource.com/137995
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Robert Griesemer 2018-09-26 20:35:05 -07:00
parent ef4a2a23bb
commit b14f328a62
8 changed files with 285 additions and 82 deletions

View File

@ -7,7 +7,8 @@
package gccgoimporter package gccgoimporter
var aliasTests = []importerTest{ var aliasTests = []importerTest{
{pkgpath: "alias", name: "IntAlias2", want: "type IntAlias2 = Int"}, {pkgpath: "aliases", name: "A14", want: "type A14 = func(int, T0) chan T2"},
{pkgpath: "aliases", name: "C0", want: "type C0 struct{f1 C1; f2 C1}"},
} }
func init() { func init() {

View File

@ -104,7 +104,11 @@ var importerTests = []importerTest{
{pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"}, {pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
{pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"}, {pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}}, {pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
// moved to importer19_test.go (they import interface types)
// {pkgpath: "aliases", name: "A14", want: "type A14 = func(int, T0) chan T2"},
// {pkgpath: "aliases", name: "C0", want: "type C0 struct{f1 C1; f2 C1}"},
{pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"}, {pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"},
{pkgpath: "issue27856", name: "M", want: "type M struct{E F}"},
} }
func TestGoxImporter(t *testing.T) { func TestGoxImporter(t *testing.T) {

View File

@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package gccgoimporter // This is a verbatim copy of $GOROOT/src/go/internal/gccgoimporter/parser.go
// with a small modification in parseInterface to support older Go versions.
// This is a verbatim copy of $GOROOT/src/go/internal/gccgoimporter/parser.go. package gccgoimporter
import ( import (
"bytes" "bytes"
@ -28,7 +29,7 @@ type parser struct {
pkgname string // name of imported package pkgname string // name of imported package
pkg *types.Package // reference to imported package pkg *types.Package // reference to imported package
imports map[string]*types.Package // package path -> package object imports map[string]*types.Package // package path -> package object
typeMap map[int]types.Type // type number -> type typeList []types.Type // type number -> type
initdata InitData // package init priority data initdata InitData // package init priority data
} }
@ -40,7 +41,7 @@ func (p *parser) init(filename string, src io.Reader, imports map[string]*types.
p.scanner.Filename = filename // for good error messages p.scanner.Filename = filename // for good error messages
p.next() p.next()
p.imports = imports p.imports = imports
p.typeMap = make(map[int]types.Type) p.typeList = make([]types.Type, 1 /* type numbers start at 1 */, 16)
} }
type importError struct { type importError struct {
@ -380,52 +381,80 @@ func (p *parser) parseConst(pkg *types.Package) *types.Const {
return types.NewConst(token.NoPos, pkg, name, typ, val) return types.NewConst(token.NoPos, pkg, name, typ, val)
} }
// reserved is a singleton type used to fill type map slots that have
// been reserved (i.e., for which a type number has been parsed) but
// which don't have their actual type yet. When the type map is updated,
// the actual type must replace a reserved entry (or we have an internal
// error). Used for self-verification only - not required for correctness.
var reserved = new(struct{ types.Type })
// reserve reserves the type map entry n for future use.
func (p *parser) reserve(n int) {
if n != len(p.typeList) {
p.errorf("invalid type number %d (out of sync)", n)
}
p.typeList = append(p.typeList, reserved)
}
// update sets the type map entries for the given type numbers nlist to t.
func (p *parser) update(t types.Type, nlist []int) {
for _, n := range nlist {
if p.typeList[n] != reserved {
p.errorf("typeMap[%d] not reserved", n)
}
p.typeList[n] = t
}
}
// NamedType = TypeName [ "=" ] Type { Method } . // NamedType = TypeName [ "=" ] Type { Method } .
// TypeName = ExportedName . // TypeName = ExportedName .
// Method = "func" "(" Param ")" Name ParamList ResultList ";" . // Method = "func" "(" Param ")" Name ParamList ResultList ";" .
func (p *parser) parseNamedType(n int) types.Type { func (p *parser) parseNamedType(nlist []int) types.Type {
pkg, name := p.parseExportedName() pkg, name := p.parseExportedName()
scope := pkg.Scope() scope := pkg.Scope()
obj := scope.Lookup(name)
if p.tok == '=' { if obj != nil && obj.Type() == nil {
// type alias p.errorf("%v has nil type", obj)
p.next()
typ := p.parseType(pkg)
if obj := scope.Lookup(name); obj != nil {
typ = obj.Type() // use previously imported type
if typ == nil {
p.errorf("%v (type alias) used in cycle", obj)
}
} else {
obj = types.NewTypeName(token.NoPos, pkg, name, typ)
scope.Insert(obj)
}
p.typeMap[n] = typ
return typ
} }
// named type // type alias
obj := scope.Lookup(name) if p.tok == '=' {
p.next()
if obj != nil {
// use the previously imported (canonical) type
t := obj.Type()
p.update(t, nlist)
p.parseType(pkg) // discard
return t
}
t := p.parseType(pkg, nlist...)
obj = types.NewTypeName(token.NoPos, pkg, name, t)
scope.Insert(obj)
return t
}
// defined type
if obj == nil { if obj == nil {
// a named type may be referred to before the underlying type // A named type may be referred to before the underlying type
// is known - set it up // is known - set it up.
tname := types.NewTypeName(token.NoPos, pkg, name, nil) tname := types.NewTypeName(token.NoPos, pkg, name, nil)
types.NewNamed(tname, nil, nil) types.NewNamed(tname, nil, nil)
scope.Insert(tname) scope.Insert(tname)
obj = tname obj = tname
} }
typ := obj.Type() // use the previously imported (canonical), or newly created type
p.typeMap[n] = typ t := obj.Type()
p.update(t, nlist)
nt, ok := typ.(*types.Named) nt, ok := t.(*types.Named)
if !ok { if !ok {
// This can happen for unsafe.Pointer, which is a TypeName holding a Basic type. // This can happen for unsafe.Pointer, which is a TypeName holding a Basic type.
pt := p.parseType(pkg) pt := p.parseType(pkg)
if pt != typ { if pt != t {
p.error("unexpected underlying type for non-named TypeName") p.error("unexpected underlying type for non-named TypeName")
} }
return typ return t
} }
underlying := p.parseType(pkg) underlying := p.parseType(pkg)
@ -451,41 +480,70 @@ func (p *parser) parseNamedType(n int) types.Type {
return nt return nt
} }
func (p *parser) parseInt() int64 { func (p *parser) parseInt64() int64 {
lit := p.expect(scanner.Int) lit := p.expect(scanner.Int)
n, err := strconv.ParseInt(lit, 10, 0) n, err := strconv.ParseInt(lit, 10, 64)
if err != nil { if err != nil {
p.error(err) p.error(err)
} }
return n return n
} }
func (p *parser) parseInt() int {
lit := p.expect(scanner.Int)
n, err := strconv.ParseInt(lit, 10, 0 /* int */)
if err != nil {
p.error(err)
}
return int(n)
}
// ArrayOrSliceType = "[" [ int ] "]" Type . // ArrayOrSliceType = "[" [ int ] "]" Type .
func (p *parser) parseArrayOrSliceType(pkg *types.Package) types.Type { func (p *parser) parseArrayOrSliceType(pkg *types.Package, nlist []int) types.Type {
p.expect('[') p.expect('[')
if p.tok == ']' { if p.tok == ']' {
p.next() p.next()
return types.NewSlice(p.parseType(pkg))
t := new(types.Slice)
p.update(t, nlist)
*t = *types.NewSlice(p.parseType(pkg))
return t
} }
n := p.parseInt() t := new(types.Array)
p.update(t, nlist)
len := p.parseInt64()
p.expect(']') p.expect(']')
return types.NewArray(p.parseType(pkg), n)
*t = *types.NewArray(p.parseType(pkg), len)
return t
} }
// MapType = "map" "[" Type "]" Type . // MapType = "map" "[" Type "]" Type .
func (p *parser) parseMapType(pkg *types.Package) types.Type { func (p *parser) parseMapType(pkg *types.Package, nlist []int) types.Type {
p.expectKeyword("map") p.expectKeyword("map")
t := new(types.Map)
p.update(t, nlist)
p.expect('[') p.expect('[')
key := p.parseType(pkg) key := p.parseType(pkg)
p.expect(']') p.expect(']')
elem := p.parseType(pkg) elem := p.parseType(pkg)
return types.NewMap(key, elem)
*t = *types.NewMap(key, elem)
return t
} }
// ChanType = "chan" ["<-" | "-<"] Type . // ChanType = "chan" ["<-" | "-<"] Type .
func (p *parser) parseChanType(pkg *types.Package) types.Type { func (p *parser) parseChanType(pkg *types.Package, nlist []int) types.Type {
p.expectKeyword("chan") p.expectKeyword("chan")
t := new(types.Chan)
p.update(t, nlist)
dir := types.SendRecv dir := types.SendRecv
switch p.tok { switch p.tok {
case '-': case '-':
@ -502,13 +560,17 @@ func (p *parser) parseChanType(pkg *types.Package) types.Type {
} }
} }
return types.NewChan(dir, p.parseType(pkg)) *t = *types.NewChan(dir, p.parseType(pkg))
return t
} }
// StructType = "struct" "{" { Field } "}" . // StructType = "struct" "{" { Field } "}" .
func (p *parser) parseStructType(pkg *types.Package) types.Type { func (p *parser) parseStructType(pkg *types.Package, nlist []int) types.Type {
p.expectKeyword("struct") p.expectKeyword("struct")
t := new(types.Struct)
p.update(t, nlist)
var fields []*types.Var var fields []*types.Var
var tags []string var tags []string
@ -521,7 +583,8 @@ func (p *parser) parseStructType(pkg *types.Package) types.Type {
} }
p.expect('}') p.expect('}')
return types.NewStruct(fields, tags) *t = *types.NewStruct(fields, tags)
return t
} }
// ParamList = "(" [ { Parameter "," } Parameter ] ")" . // ParamList = "(" [ { Parameter "," } Parameter ] ")" .
@ -564,10 +627,15 @@ func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
} }
// FunctionType = ParamList ResultList . // FunctionType = ParamList ResultList .
func (p *parser) parseFunctionType(pkg *types.Package) *types.Signature { func (p *parser) parseFunctionType(pkg *types.Package, nlist []int) *types.Signature {
t := new(types.Signature)
p.update(t, nlist)
params, isVariadic := p.parseParamList(pkg) params, isVariadic := p.parseParamList(pkg)
results := p.parseResultList(pkg) results := p.parseResultList(pkg)
return types.NewSignature(nil, params, results, isVariadic)
*t = *types.NewSignature(nil, params, results, isVariadic)
return t
} }
// Func = Name FunctionType . // Func = Name FunctionType .
@ -579,13 +647,16 @@ func (p *parser) parseFunc(pkg *types.Package) *types.Func {
p.discardDirectiveWhileParsingTypes(pkg) p.discardDirectiveWhileParsingTypes(pkg)
return nil return nil
} }
return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg)) return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg, nil))
} }
// InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" . // InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" .
func (p *parser) parseInterfaceType(pkg *types.Package) types.Type { func (p *parser) parseInterfaceType(pkg *types.Package, nlist []int) types.Type {
p.expectKeyword("interface") p.expectKeyword("interface")
t := new(types.Interface)
p.update(t, nlist)
var methods []*types.Func var methods []*types.Func
var embeddeds []types.Type var embeddeds []types.Type
@ -602,53 +673,61 @@ func (p *parser) parseInterfaceType(pkg *types.Package) types.Type {
} }
p.expect('}') p.expect('}')
return newInterface(methods, embeddeds) *t = *newInterface(methods, embeddeds)
return t
} }
// PointerType = "*" ("any" | Type) . // PointerType = "*" ("any" | Type) .
func (p *parser) parsePointerType(pkg *types.Package) types.Type { func (p *parser) parsePointerType(pkg *types.Package, nlist []int) types.Type {
p.expect('*') p.expect('*')
if p.tok == scanner.Ident { if p.tok == scanner.Ident {
p.expectKeyword("any") p.expectKeyword("any")
return types.Typ[types.UnsafePointer] t := types.Typ[types.UnsafePointer]
p.update(t, nlist)
return t
} }
return types.NewPointer(p.parseType(pkg))
t := new(types.Pointer)
p.update(t, nlist)
*t = *types.NewPointer(p.parseType(pkg))
return t
} }
// TypeDefinition = NamedType | MapType | ChanType | StructType | InterfaceType | PointerType | ArrayOrSliceType | FunctionType . // TypeSpec = NamedType | MapType | ChanType | StructType | InterfaceType | PointerType | ArrayOrSliceType | FunctionType .
func (p *parser) parseTypeDefinition(pkg *types.Package, n int) types.Type { func (p *parser) parseTypeSpec(pkg *types.Package, nlist []int) types.Type {
var t types.Type
switch p.tok { switch p.tok {
case scanner.String: case scanner.String:
t = p.parseNamedType(n) return p.parseNamedType(nlist)
case scanner.Ident: case scanner.Ident:
switch p.lit { switch p.lit {
case "map": case "map":
t = p.parseMapType(pkg) return p.parseMapType(pkg, nlist)
case "chan": case "chan":
t = p.parseChanType(pkg) return p.parseChanType(pkg, nlist)
case "struct": case "struct":
t = p.parseStructType(pkg) return p.parseStructType(pkg, nlist)
case "interface": case "interface":
t = p.parseInterfaceType(pkg) return p.parseInterfaceType(pkg, nlist)
} }
case '*': case '*':
t = p.parsePointerType(pkg) return p.parsePointerType(pkg, nlist)
case '[': case '[':
t = p.parseArrayOrSliceType(pkg) return p.parseArrayOrSliceType(pkg, nlist)
case '(': case '(':
t = p.parseFunctionType(pkg) return p.parseFunctionType(pkg, nlist)
} }
p.typeMap[n] = t p.errorf("expected type name or literal, got %s", scanner.TokenString(p.tok))
return t return nil
} }
const ( const (
@ -702,29 +781,36 @@ func lookupBuiltinType(typ int) types.Type {
}[typ] }[typ]
} }
// Type = "<" "type" ( "-" int | int [ TypeDefinition ] ) ">" . // Type = "<" "type" ( "-" int | int [ TypeSpec ] ) ">" .
func (p *parser) parseType(pkg *types.Package) (t types.Type) { //
// parseType updates the type map to t for all type numbers n.
//
func (p *parser) parseType(pkg *types.Package, n ...int) (t types.Type) {
p.expect('<') p.expect('<')
p.expectKeyword("type") p.expectKeyword("type")
switch p.tok { switch p.tok {
case scanner.Int: case scanner.Int:
n := p.parseInt() n1 := p.parseInt()
if p.tok == '>' { if p.tok == '>' {
t = p.typeMap[int(n)] t = p.typeList[n1]
if t == reserved {
p.errorf("invalid type cycle, type %d not yet defined", n1)
}
p.update(t, n)
} else { } else {
t = p.parseTypeDefinition(pkg, int(n)) p.reserve(n1)
t = p.parseTypeSpec(pkg, append(n, n1))
} }
case '-': case '-':
p.next() p.next()
n := p.parseInt() n1 := p.parseInt()
t = lookupBuiltinType(int(n)) t = lookupBuiltinType(n1)
p.update(t, n)
default: default:
p.errorf("expected type number, got %s (%q)", scanner.TokenString(p.tok), p.lit) p.errorf("expected type number, got %s (%q)", scanner.TokenString(p.tok), p.lit)
return nil
} }
p.expect('>') p.expect('>')
@ -737,7 +823,7 @@ func (p *parser) parsePackageInit() PackageInit {
initfunc := p.parseUnquotedString() initfunc := p.parseUnquotedString()
priority := -1 priority := -1
if p.version == "v1" { if p.version == "v1" {
priority = int(p.parseInt()) priority = p.parseInt()
} }
return PackageInit{Name: name, InitFunc: initfunc, Priority: priority} return PackageInit{Name: name, InitFunc: initfunc, Priority: priority}
} }
@ -783,7 +869,7 @@ func (p *parser) parseInitDataDirective() {
case "priority": case "priority":
p.next() p.next()
p.initdata.Priority = int(p.parseInt()) p.initdata.Priority = p.parseInt()
p.expect(';') p.expect(';')
case "init": case "init":
@ -797,8 +883,8 @@ func (p *parser) parseInitDataDirective() {
p.next() p.next()
// The graph data is thrown away for now. // The graph data is thrown away for now.
for p.tok != ';' && p.tok != scanner.EOF { for p.tok != ';' && p.tok != scanner.EOF {
p.parseInt() p.parseInt64()
p.parseInt() p.parseInt64()
} }
p.expect(';') p.expect(';')
@ -900,7 +986,7 @@ func (p *parser) parsePackage() *types.Package {
for p.tok != scanner.EOF { for p.tok != scanner.EOF {
p.parseDirective() p.parseDirective()
} }
for _, typ := range p.typeMap { for _, typ := range p.typeList {
if it, ok := typ.(*types.Interface); ok { if it, ok := typ.(*types.Interface); ok {
it.Complete() it.Complete()
} }

View File

@ -1,4 +0,0 @@
v1;
package alias;
pkgpath alias;
type <type 115 "I1" <type 116 interface { M1 (? <type 117 "IntAlias2" = <type 118 "IntAlias" = <type 119 "Int" <type -11>>>>) < type 114>; M2 () <type 1>; }>>;

View File

@ -0,0 +1,65 @@
package aliases
type (
T0 [10]int
T1 []byte
T2 struct {
x int
}
T3 interface {
m() T2
}
T4 func(int, T0) chan T2
)
// basic aliases
type (
Ai = int
A0 = T0
A1 = T1
A2 = T2
A3 = T3
A4 = T4
A10 = [10]int
A11 = []byte
A12 = struct {
x int
}
A13 = interface {
m() A2
}
A14 = func(int, A0) chan A2
)
// alias receiver types
func (T0) m1() {}
func (A0) m2() {}
// alias receiver types (long type declaration chains)
type (
V0 = V1
V1 = (V2)
V2 = (V3)
V3 = T0
)
func (V1) n() {}
// cycles
type C0 struct {
f1 C1
f2 C2
}
type (
C1 *C0
C2 = C1
)
type (
C5 struct {
f *C6
}
C6 = C5
)

View File

@ -0,0 +1,33 @@
v2;
package aliases;
prefix go;
package aliases go.aliases go.aliases;
type <type 1 "A0" = <type 2 "T0" <type 3 [10 ] <type -11>>
func (? <esc:0x1> <type 2>) .go.aliases.m1 ();
func (? <esc:0x1> <type 1>) .go.aliases.m2 ();
func (? <esc:0x1> <type 4 "V1" = <type 5 "V2" = <type 6 "V3" = <type 2>>>>) .go.aliases.n ();
>>;
type <type 7 "A1" = <type 8 "T1" <type 9 [] <type -20>>>>;
type <type 10 "A10" = <type 11 [10 ] <type -11>>>;
type <type 12 "A11" = <type 13 [] <type -20>>>;
type <type 14 "A12" = <type 15 struct { .go.aliases.x <type -11>; }>>;
type <type 16 "A13" = <type 17 interface { .go.aliases.m () <type 18 "A2" = <type 19 "T2" <type 20 struct { .go.aliases.x <type -11>; }>>>; }>>;
type <type 21 "A14" = <type 22 (? <type -11>, ? <type 1>) <type 23 chan <type 18>>>>;
type <type 18>;
type <type 24 "A3" = <type 25 "T3" <type 26 interface { .go.aliases.m () <type 19>; }>>>;
type <type 27 "A4" = <type 28 "T4" <type 29 (? <type -11>, ? <type 2>) <type 30 chan <type 19>>>>>;
type <type 31 "Ai" = <type -11>>;
type <type 32 "C0" <type 33 struct { .go.aliases.f1 <type 34 "C1" <type 35 *<type 32>>>; .go.aliases.f2 <type 36 "C2" = <type 34>>; }>>;
type <type 34>;
type <type 36>;
type <type 37 "C5" <type 38 struct { .go.aliases.f <type 39 *<type 40 "C6" = <type 37>>>; }>>;
type <type 40>;
type <type 2>;
type <type 8>;
type <type 19>;
type <type 25>;
type <type 28>;
type <type 41 "V0" = <type 4>>;
type <type 4>;
type <type 5>;
type <type 6>;

View File

@ -0,0 +1,9 @@
package lib
type M struct {
E E
}
type F struct {
_ *M
}
type E = F

View File

@ -0,0 +1,9 @@
v2;
package main;
pkgpath main;
import runtime runtime "runtime";
init runtime runtime..import sys runtime_internal_sys..import;
init_graph 0 1;
type <type 1 "E" = <type 2 "F" <type 3 struct { .main._ <type 4 *<type 5 "M" <type 6 struct { E <type 1>; }>>>; }>>>;
type <type 2>;
type <type 5>;