mirror of
https://github.com/golang/go
synced 2024-11-02 09:28:34 +00:00
[dev.typeparams] cmd/compile: add derived-type dictionaries to unified IR
This CL updates the unified IR export data serialization to explicitly and separately record the derived types used by a declaration. The readers currently just use this data to construct types/IR the same as before, but eventually we can use it for emitting GC-shape dictionaries. Change-Id: I7d67ad9b3f1fbe69664bf19e056bc94f73507220 Reviewed-on: https://go-review.googlesource.com/c/go/+/331829 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com> Trust: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
6a5f7e8498
commit
f503740ccf
6 changed files with 381 additions and 223 deletions
|
@ -134,11 +134,15 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
w := l.pw.newEncoderRaw(relocObj)
|
w := l.pw.newEncoderRaw(relocObj)
|
||||||
bside := l.pw.newEncoderRaw(relocObjExt)
|
wext := l.pw.newEncoderRaw(relocObjExt)
|
||||||
assert(bside.idx == w.idx)
|
wdict := l.pw.newEncoderRaw(relocObjDict)
|
||||||
|
|
||||||
l.decls[sym] = w.idx
|
l.decls[sym] = w.idx
|
||||||
|
assert(wext.idx == w.idx)
|
||||||
|
assert(wdict.idx == w.idx)
|
||||||
|
|
||||||
l.relocCommon(pr, &w, relocObj, idx)
|
l.relocCommon(pr, &w, relocObj, idx)
|
||||||
|
l.relocCommon(pr, &wdict, relocObjDict, idx)
|
||||||
|
|
||||||
var obj *ir.Name
|
var obj *ir.Name
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
@ -153,18 +157,18 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
bside.sync(syncObject1)
|
wext.sync(syncObject1)
|
||||||
switch tag {
|
switch tag {
|
||||||
case objFunc:
|
case objFunc:
|
||||||
l.relocFuncExt(&bside, obj)
|
l.relocFuncExt(&wext, obj)
|
||||||
case objType:
|
case objType:
|
||||||
l.relocTypeExt(&bside, obj)
|
l.relocTypeExt(&wext, obj)
|
||||||
case objVar:
|
case objVar:
|
||||||
l.relocVarExt(&bside, obj)
|
l.relocVarExt(&wext, obj)
|
||||||
}
|
}
|
||||||
bside.flush()
|
wext.flush()
|
||||||
} else {
|
} else {
|
||||||
l.relocCommon(pr, &bside, relocObjExt, idx)
|
l.relocCommon(pr, &wext, relocObjExt, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.idx
|
return w.idx
|
||||||
|
@ -286,7 +290,17 @@ func (pr *pkgDecoder) peekObj(idx int) (string, string, codeObj, []int) {
|
||||||
bounds := make([]int, r.len())
|
bounds := make([]int, r.len())
|
||||||
for i := range bounds {
|
for i := range bounds {
|
||||||
r.sync(syncType)
|
r.sync(syncType)
|
||||||
bounds[i] = r.reloc(relocType)
|
if r.bool() {
|
||||||
|
r.len()
|
||||||
|
} else {
|
||||||
|
r.reloc(relocType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(mdempsky): This result now needs to include the 'derived'
|
||||||
|
// bool too, but none of the callers currently depend on it
|
||||||
|
// anyway. Either fix it to be meaningful, or just get rid of it
|
||||||
|
// altogether.
|
||||||
|
bounds[i] = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
tag := codeObj(r.code(syncCodeObj))
|
tag := codeObj(r.code(syncCodeObj))
|
||||||
|
|
|
@ -56,12 +56,12 @@ func newPkgReader(pr pkgDecoder) *pkgReader {
|
||||||
type pkgReaderIndex struct {
|
type pkgReaderIndex struct {
|
||||||
pr *pkgReader
|
pr *pkgReader
|
||||||
idx int
|
idx int
|
||||||
implicits []*types.Type
|
dict *readerDict
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pri pkgReaderIndex) asReader(k reloc, marker syncMarker) *reader {
|
func (pri pkgReaderIndex) asReader(k reloc, marker syncMarker) *reader {
|
||||||
r := pri.pr.newReader(k, pri.idx, marker)
|
r := pri.pr.newReader(k, pri.idx, marker)
|
||||||
r.implicits = pri.implicits
|
r.dict = pri.dict
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,29 +77,10 @@ type reader struct {
|
||||||
|
|
||||||
p *pkgReader
|
p *pkgReader
|
||||||
|
|
||||||
// Implicit and explicit type arguments in use for reading the
|
|
||||||
// current object. For example:
|
|
||||||
//
|
|
||||||
// func F[T any]() {
|
|
||||||
// type X[U any] struct { t T; u U }
|
|
||||||
// var _ X[string]
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var _ = F[int]
|
|
||||||
//
|
|
||||||
// While instantiating F[int], we need to in turn instantiate
|
|
||||||
// X[string]. [int] and [string] are explicit type arguments for F
|
|
||||||
// and X, respectively; but [int] is also the implicit type
|
|
||||||
// arguments for X.
|
|
||||||
//
|
|
||||||
// (As an analogy to function literals, explicits are the function
|
|
||||||
// literal's formal parameters, while implicits are variables
|
|
||||||
// captured by the function literal.)
|
|
||||||
implicits []*types.Type
|
|
||||||
explicits []*types.Type
|
|
||||||
|
|
||||||
ext *reader
|
ext *reader
|
||||||
|
|
||||||
|
dict *readerDict
|
||||||
|
|
||||||
// TODO(mdempsky): The state below is all specific to reading
|
// TODO(mdempsky): The state below is all specific to reading
|
||||||
// function bodies. It probably makes sense to split it out
|
// function bodies. It probably makes sense to split it out
|
||||||
// separately so that it doesn't take up space in every reader
|
// separately so that it doesn't take up space in every reader
|
||||||
|
@ -135,6 +116,35 @@ type reader struct {
|
||||||
inlvars, retvars ir.Nodes
|
inlvars, retvars ir.Nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type readerDict struct {
|
||||||
|
// targs holds the implicit and explicit type arguments in use for
|
||||||
|
// reading the current object. For example:
|
||||||
|
//
|
||||||
|
// func F[T any]() {
|
||||||
|
// type X[U any] struct { t T; u U }
|
||||||
|
// var _ X[string]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var _ = F[int]
|
||||||
|
//
|
||||||
|
// While instantiating F[int], we need to in turn instantiate
|
||||||
|
// X[string]. [int] and [string] are explicit type arguments for F
|
||||||
|
// and X, respectively; but [int] is also the implicit type
|
||||||
|
// arguments for X.
|
||||||
|
//
|
||||||
|
// (As an analogy to function literals, explicits are the function
|
||||||
|
// literal's formal parameters, while implicits are variables
|
||||||
|
// captured by the function literal.)
|
||||||
|
targs []*types.Type
|
||||||
|
|
||||||
|
// implicits counts how many of types within targs are implicit type
|
||||||
|
// arguments; the rest are explicit.
|
||||||
|
implicits int
|
||||||
|
|
||||||
|
derivedReloc []int // reloc index of the derived type's descriptor
|
||||||
|
derived []*types.Type // slice of previously computed derived types
|
||||||
|
}
|
||||||
|
|
||||||
func (r *reader) setType(n ir.Node, typ *types.Type) {
|
func (r *reader) setType(n ir.Node, typ *types.Type) {
|
||||||
n.SetType(typ)
|
n.SetType(typ)
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
|
@ -283,17 +293,28 @@ func (r *reader) doPkg() *types.Pkg {
|
||||||
|
|
||||||
func (r *reader) typ() *types.Type {
|
func (r *reader) typ() *types.Type {
|
||||||
r.sync(syncType)
|
r.sync(syncType)
|
||||||
return r.p.typIdx(r.reloc(relocType), r.implicits, r.explicits)
|
if r.bool() {
|
||||||
|
return r.p.typIdx(r.len(), r.dict)
|
||||||
|
}
|
||||||
|
return r.p.typIdx(r.reloc(relocType), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pr *pkgReader) typIdx(idx int, implicits, explicits []*types.Type) *types.Type {
|
func (pr *pkgReader) typIdx(idx int, dict *readerDict) *types.Type {
|
||||||
if typ := pr.typs[idx]; typ != nil {
|
var where **types.Type
|
||||||
|
if dict != nil {
|
||||||
|
where = &dict.derived[idx]
|
||||||
|
idx = dict.derivedReloc[idx]
|
||||||
|
} else {
|
||||||
|
where = &pr.typs[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
if typ := *where; typ != nil {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
r := pr.newReader(relocType, idx, syncTypeIdx)
|
r := pr.newReader(relocType, idx, syncTypeIdx)
|
||||||
r.implicits = implicits
|
r.dict = dict
|
||||||
r.explicits = explicits
|
|
||||||
typ := r.doTyp()
|
typ := r.doTyp()
|
||||||
assert(typ != nil)
|
assert(typ != nil)
|
||||||
|
|
||||||
|
@ -336,20 +357,12 @@ func (pr *pkgReader) typIdx(idx int, implicits, explicits []*types.Type) *types.
|
||||||
//
|
//
|
||||||
// The idx 1, corresponding with type I was resolved successfully
|
// The idx 1, corresponding with type I was resolved successfully
|
||||||
// after r.doTyp() call.
|
// after r.doTyp() call.
|
||||||
if typ := pr.typs[idx]; typ != nil {
|
|
||||||
return typ
|
if prev := *where; prev != nil {
|
||||||
|
return prev
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have type parameters, the type might refer to them, and it
|
*where = typ
|
||||||
// wouldn't be safe to reuse those in other contexts. So we
|
|
||||||
// conservatively avoid caching them in that case.
|
|
||||||
//
|
|
||||||
// TODO(mdempsky): If we're clever, we should be able to still cache
|
|
||||||
// types by tracking which type parameters are used. However, in my
|
|
||||||
// attempts so far, I haven't yet succeeded in being clever enough.
|
|
||||||
if !r.hasTypeParams() {
|
|
||||||
pr.typs[idx] = typ
|
|
||||||
}
|
|
||||||
|
|
||||||
if !typ.IsUntyped() {
|
if !typ.IsUntyped() {
|
||||||
types.CheckSize(typ)
|
types.CheckSize(typ)
|
||||||
|
@ -372,11 +385,7 @@ func (r *reader) doTyp() *types.Type {
|
||||||
return obj.Type()
|
return obj.Type()
|
||||||
|
|
||||||
case typeTypeParam:
|
case typeTypeParam:
|
||||||
idx := r.len()
|
return r.dict.targs[r.len()]
|
||||||
if idx < len(r.implicits) {
|
|
||||||
return r.implicits[idx]
|
|
||||||
}
|
|
||||||
return r.explicits[idx-len(r.implicits)]
|
|
||||||
|
|
||||||
case typeArray:
|
case typeArray:
|
||||||
len := int64(r.uint64())
|
len := int64(r.uint64())
|
||||||
|
@ -490,7 +499,12 @@ func (r *reader) obj() ir.Node {
|
||||||
explicits[i] = r.typ()
|
explicits[i] = r.typ()
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.p.objIdx(idx, r.implicits, explicits)
|
var implicits []*types.Type
|
||||||
|
if r.dict != nil {
|
||||||
|
implicits = r.dict.targs
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.p.objIdx(idx, implicits, explicits)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node {
|
func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node {
|
||||||
|
@ -499,14 +513,11 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
|
||||||
|
|
||||||
_, sym := r.qualifiedIdent()
|
_, sym := r.qualifiedIdent()
|
||||||
|
|
||||||
// Middle dot indicates local defined type; see writer.sym.
|
dict := &readerDict{}
|
||||||
// TODO(mdempsky): Come up with a better way to handle this.
|
r.dict = dict
|
||||||
if strings.Contains(sym.Name, "·") {
|
r.ext.dict = dict
|
||||||
r.implicits = implicits
|
|
||||||
r.ext.implicits = implicits
|
r.typeParamBounds(sym, implicits, explicits)
|
||||||
}
|
|
||||||
r.explicits = explicits
|
|
||||||
r.ext.explicits = explicits
|
|
||||||
|
|
||||||
origSym := sym
|
origSym := sym
|
||||||
|
|
||||||
|
@ -515,9 +526,17 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
|
||||||
return sym.Def.(ir.Node)
|
return sym.Def.(ir.Node)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.typeParamBounds(origSym)
|
|
||||||
tag := codeObj(r.code(syncCodeObj))
|
tag := codeObj(r.code(syncCodeObj))
|
||||||
|
|
||||||
|
{
|
||||||
|
rdict := pr.newReader(relocObjDict, idx, syncObject1)
|
||||||
|
r.dict.derivedReloc = make([]int, rdict.len())
|
||||||
|
r.dict.derived = make([]*types.Type, len(r.dict.derivedReloc))
|
||||||
|
for i := range r.dict.derived {
|
||||||
|
r.dict.derivedReloc[i] = rdict.reloc(relocType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
do := func(op ir.Op, hasTParams bool) *ir.Name {
|
do := func(op ir.Op, hasTParams bool) *ir.Name {
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
if hasTParams {
|
if hasTParams {
|
||||||
|
@ -542,7 +561,7 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node
|
||||||
|
|
||||||
case objStub:
|
case objStub:
|
||||||
if pri, ok := objReader[origSym]; ok {
|
if pri, ok := objReader[origSym]; ok {
|
||||||
return pri.pr.objIdx(pri.idx, pri.implicits, r.explicits)
|
return pri.pr.objIdx(pri.idx, nil, explicits)
|
||||||
}
|
}
|
||||||
if haveLegacyImports {
|
if haveLegacyImports {
|
||||||
assert(!r.hasTypeParams())
|
assert(!r.hasTypeParams())
|
||||||
|
@ -621,46 +640,50 @@ func (r *reader) mangle(sym *types.Sym) *types.Sym {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(sym.Name)
|
buf.WriteString(sym.Name)
|
||||||
buf.WriteByte('[')
|
buf.WriteByte('[')
|
||||||
for i, targs := range [2][]*types.Type{r.implicits, r.explicits} {
|
for i, targ := range r.dict.targs {
|
||||||
if i > 0 && len(r.implicits) != 0 && len(r.explicits) != 0 {
|
if i > 0 {
|
||||||
|
if i == r.dict.implicits {
|
||||||
buf.WriteByte(';')
|
buf.WriteByte(';')
|
||||||
}
|
} else {
|
||||||
for j, targ := range targs {
|
|
||||||
if j > 0 {
|
|
||||||
buf.WriteByte(',')
|
buf.WriteByte(',')
|
||||||
}
|
}
|
||||||
// TODO(mdempsky): We need the linker to replace "" in the symbol
|
|
||||||
// names here.
|
|
||||||
buf.WriteString(targ.LinkString())
|
|
||||||
}
|
}
|
||||||
|
buf.WriteString(targ.LinkString())
|
||||||
}
|
}
|
||||||
buf.WriteByte(']')
|
buf.WriteByte(']')
|
||||||
return sym.Pkg.Lookup(buf.String())
|
return sym.Pkg.Lookup(buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader) typeParamBounds(sym *types.Sym) {
|
func (r *reader) typeParamBounds(sym *types.Sym, implicits, explicits []*types.Type) {
|
||||||
r.sync(syncTypeParamBounds)
|
r.sync(syncTypeParamBounds)
|
||||||
|
|
||||||
nimplicits := r.len()
|
nimplicits := r.len()
|
||||||
nexplicits := r.len()
|
nexplicits := r.len()
|
||||||
|
|
||||||
if len(r.implicits) != nimplicits || len(r.explicits) != nexplicits {
|
if nimplicits > len(implicits) || nexplicits != len(explicits) {
|
||||||
base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(r.implicits), len(r.explicits))
|
base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.dict.targs = append(implicits[:nimplicits:nimplicits], explicits...)
|
||||||
|
r.dict.implicits = nimplicits
|
||||||
|
|
||||||
// For stenciling, we can just skip over the type parameters.
|
// For stenciling, we can just skip over the type parameters.
|
||||||
|
|
||||||
for range r.explicits {
|
for range r.dict.targs[r.dict.implicits:] {
|
||||||
// Skip past bounds without actually evaluating them.
|
// Skip past bounds without actually evaluating them.
|
||||||
r.sync(syncType)
|
r.sync(syncType)
|
||||||
|
if r.bool() {
|
||||||
|
r.len()
|
||||||
|
} else {
|
||||||
r.reloc(relocType)
|
r.reloc(relocType)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader) typeParamNames() {
|
func (r *reader) typeParamNames() {
|
||||||
r.sync(syncTypeParamNames)
|
r.sync(syncTypeParamNames)
|
||||||
|
|
||||||
for range r.explicits {
|
for range r.dict.targs[r.dict.implicits:] {
|
||||||
r.pos()
|
r.pos()
|
||||||
r.localIdent()
|
r.localIdent()
|
||||||
}
|
}
|
||||||
|
@ -729,7 +752,7 @@ func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader) hasTypeParams() bool {
|
func (r *reader) hasTypeParams() bool {
|
||||||
return len(r.implicits)+len(r.explicits) != 0
|
return r.dict != nil && len(r.dict.targs) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// @@@ Compiler extensions
|
// @@@ Compiler extensions
|
||||||
|
@ -776,10 +799,10 @@ func (r *reader) funcExt(name *ir.Name) {
|
||||||
Cost: int32(r.len()),
|
Cost: int32(r.len()),
|
||||||
CanDelayResults: r.bool(),
|
CanDelayResults: r.bool(),
|
||||||
}
|
}
|
||||||
r.addBody(name.Func, r.explicits)
|
r.addBody(name.Func)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
r.addBody(name.Func, r.explicits)
|
r.addBody(name.Func)
|
||||||
}
|
}
|
||||||
r.sync(syncEOF)
|
r.sync(syncEOF)
|
||||||
}
|
}
|
||||||
|
@ -795,8 +818,7 @@ func (r *reader) typeExt(name *ir.Name) {
|
||||||
// type descriptor is written out as DUPOK and method wrappers are
|
// type descriptor is written out as DUPOK and method wrappers are
|
||||||
// generated even for imported types.
|
// generated even for imported types.
|
||||||
var targs []*types.Type
|
var targs []*types.Type
|
||||||
targs = append(targs, r.implicits...)
|
targs = append(targs, r.dict.targs...)
|
||||||
targs = append(targs, r.explicits...)
|
|
||||||
typ.SetRParams(targs)
|
typ.SetRParams(targs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,8 +863,8 @@ var bodyReader = map[*ir.Func]pkgReaderIndex{}
|
||||||
// constructed.
|
// constructed.
|
||||||
var todoBodies []*ir.Func
|
var todoBodies []*ir.Func
|
||||||
|
|
||||||
func (r *reader) addBody(fn *ir.Func, implicits []*types.Type) {
|
func (r *reader) addBody(fn *ir.Func) {
|
||||||
pri := pkgReaderIndex{r.p, r.reloc(relocBody), implicits}
|
pri := pkgReaderIndex{r.p, r.reloc(relocBody), r.dict}
|
||||||
bodyReader[fn] = pri
|
bodyReader[fn] = pri
|
||||||
|
|
||||||
if r.curfn == nil {
|
if r.curfn == nil {
|
||||||
|
@ -1565,7 +1587,7 @@ func (r *reader) funcLit() ir.Node {
|
||||||
r.setType(cv, outer.Type())
|
r.setType(cv, outer.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
r.addBody(fn, r.implicits)
|
r.addBody(fn)
|
||||||
|
|
||||||
return fn.OClosure
|
return fn.OClosure
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,21 @@ type reader2 struct {
|
||||||
|
|
||||||
p *pkgReader2
|
p *pkgReader2
|
||||||
|
|
||||||
tparams []*types2.TypeName
|
dict *reader2Dict
|
||||||
|
}
|
||||||
|
|
||||||
|
type reader2Dict struct {
|
||||||
|
bounds []reader2TypeBound
|
||||||
|
|
||||||
|
tparams []*types2.TypeParam
|
||||||
|
|
||||||
|
derivedReloc []int
|
||||||
|
derived []types2.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
type reader2TypeBound struct {
|
||||||
|
derived bool
|
||||||
|
boundIdx int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pr *pkgReader2) newReader(k reloc, idx int, marker syncMarker) *reader2 {
|
func (pr *pkgReader2) newReader(k reloc, idx int, marker syncMarker) *reader2 {
|
||||||
|
@ -163,28 +177,37 @@ func (r *reader2) doPkg() *types2.Package {
|
||||||
|
|
||||||
func (r *reader2) typ() types2.Type {
|
func (r *reader2) typ() types2.Type {
|
||||||
r.sync(syncType)
|
r.sync(syncType)
|
||||||
return r.p.typIdx(r.reloc(relocType), r.tparams)
|
if r.bool() {
|
||||||
|
return r.p.typIdx(r.len(), r.dict)
|
||||||
|
}
|
||||||
|
return r.p.typIdx(r.reloc(relocType), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pr *pkgReader2) typIdx(idx int, tparams []*types2.TypeName) types2.Type {
|
func (pr *pkgReader2) typIdx(idx int, dict *reader2Dict) types2.Type {
|
||||||
if typ := pr.typs[idx]; typ != nil {
|
var where *types2.Type
|
||||||
|
if dict != nil {
|
||||||
|
where = &dict.derived[idx]
|
||||||
|
idx = dict.derivedReloc[idx]
|
||||||
|
} else {
|
||||||
|
where = &pr.typs[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
if typ := *where; typ != nil {
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
r := pr.newReader(relocType, idx, syncTypeIdx)
|
r := pr.newReader(relocType, idx, syncTypeIdx)
|
||||||
r.tparams = tparams
|
r.dict = dict
|
||||||
|
|
||||||
typ := r.doTyp()
|
typ := r.doTyp()
|
||||||
assert(typ != nil)
|
assert(typ != nil)
|
||||||
|
|
||||||
if pr.typs[idx] != nil {
|
// See comment in pkgReader.typIdx explaining how this happens.
|
||||||
// See comment in pkgReader.typIdx.
|
if prev := *where; prev != nil {
|
||||||
return pr.typs[idx]
|
return prev
|
||||||
}
|
|
||||||
|
|
||||||
if len(tparams) == 0 {
|
|
||||||
pr.typs[idx] = typ
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*where = typ
|
||||||
return typ
|
return typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,8 +229,7 @@ func (r *reader2) doTyp() (res types2.Type) {
|
||||||
return name.Type()
|
return name.Type()
|
||||||
|
|
||||||
case typeTypeParam:
|
case typeTypeParam:
|
||||||
idx := r.len()
|
return r.dict.tparams[r.len()]
|
||||||
return r.tparams[idx].Type().(*types2.TypeParam)
|
|
||||||
|
|
||||||
case typeArray:
|
case typeArray:
|
||||||
len := int64(r.uint64())
|
len := int64(r.uint64())
|
||||||
|
@ -330,10 +352,12 @@ func (r *reader2) obj() (types2.Object, []types2.Type) {
|
||||||
|
|
||||||
func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
|
func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
|
||||||
r := pr.newReader(relocObj, idx, syncObject1)
|
r := pr.newReader(relocObj, idx, syncObject1)
|
||||||
|
r.dict = &reader2Dict{}
|
||||||
|
|
||||||
objPkg, objName := r.qualifiedIdent()
|
objPkg, objName := r.qualifiedIdent()
|
||||||
assert(objName != "")
|
assert(objName != "")
|
||||||
|
|
||||||
bounds := r.typeParamBounds()
|
r.typeParamBounds()
|
||||||
tag := codeObj(r.code(syncCodeObj))
|
tag := codeObj(r.code(syncCodeObj))
|
||||||
|
|
||||||
if tag == objStub {
|
if tag == objStub {
|
||||||
|
@ -341,6 +365,15 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
|
||||||
return objPkg, objName
|
return objPkg, objName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
rdict := r.p.newReader(relocObjDict, idx, syncObject1)
|
||||||
|
r.dict.derivedReloc = make([]int, rdict.len())
|
||||||
|
r.dict.derived = make([]types2.Type, len(r.dict.derivedReloc))
|
||||||
|
for i := range r.dict.derived {
|
||||||
|
r.dict.derivedReloc[i] = rdict.reloc(relocType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
objPkg.Scope().InsertLazy(objName, func() types2.Object {
|
objPkg.Scope().InsertLazy(objName, func() types2.Object {
|
||||||
switch tag {
|
switch tag {
|
||||||
default:
|
default:
|
||||||
|
@ -358,21 +391,16 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
|
||||||
|
|
||||||
case objFunc:
|
case objFunc:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
r.typeParamNames(bounds)
|
tparams := r.typeParamNames()
|
||||||
sig := r.signature(nil)
|
sig := r.signature(nil)
|
||||||
if len(r.tparams) != 0 {
|
sig.SetTParams(tparams)
|
||||||
sig.SetTParams(r.tparams)
|
|
||||||
}
|
|
||||||
return types2.NewFunc(pos, objPkg, objName, sig)
|
return types2.NewFunc(pos, objPkg, objName, sig)
|
||||||
|
|
||||||
case objType:
|
case objType:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
|
|
||||||
return types2.NewTypeNameLazy(pos, objPkg, objName, func(named *types2.Named) (tparams []*types2.TypeName, underlying types2.Type, methods []*types2.Func) {
|
return types2.NewTypeNameLazy(pos, objPkg, objName, func(named *types2.Named) (tparams []*types2.TypeName, underlying types2.Type, methods []*types2.Func) {
|
||||||
r.typeParamNames(bounds)
|
tparams = r.typeParamNames()
|
||||||
if len(r.tparams) != 0 {
|
|
||||||
tparams = r.tparams
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(mdempsky): Rewrite receiver types to underlying is an
|
// TODO(mdempsky): Rewrite receiver types to underlying is an
|
||||||
// Interface? The go/types importer does this (I think because
|
// Interface? The go/types importer does this (I think because
|
||||||
|
@ -382,7 +410,7 @@ func (pr *pkgReader2) objIdx(idx int) (*types2.Package, string) {
|
||||||
|
|
||||||
methods = make([]*types2.Func, r.len())
|
methods = make([]*types2.Func, r.len())
|
||||||
for i := range methods {
|
for i := range methods {
|
||||||
methods[i] = r.method(bounds)
|
methods[i] = r.method()
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -403,51 +431,73 @@ func (r *reader2) value() (types2.Type, constant.Value) {
|
||||||
return r.typ(), r.rawValue()
|
return r.typ(), r.rawValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader2) typeParamBounds() []int {
|
func (r *reader2) typeParamBounds() {
|
||||||
r.sync(syncTypeParamBounds)
|
r.sync(syncTypeParamBounds)
|
||||||
|
|
||||||
// exported types never have implicit type parameters
|
if implicits := r.len(); implicits != 0 {
|
||||||
// TODO(mdempsky): Hide this from public importer.
|
base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits)
|
||||||
assert(r.len() == 0)
|
}
|
||||||
|
|
||||||
bounds := make([]int, r.len())
|
r.dict.bounds = make([]reader2TypeBound, r.len())
|
||||||
for i := range bounds {
|
for i := range r.dict.bounds {
|
||||||
r.sync(syncType)
|
b := &r.dict.bounds[i]
|
||||||
bounds[i] = r.reloc(relocType)
|
r.sync(syncType)
|
||||||
|
b.derived = r.bool()
|
||||||
|
if b.derived {
|
||||||
|
b.boundIdx = r.len()
|
||||||
|
} else {
|
||||||
|
b.boundIdx = r.reloc(relocType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return bounds
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader2) typeParamNames(bounds []int) {
|
func (r *reader2) typeParamNames() []*types2.TypeName {
|
||||||
r.sync(syncTypeParamNames)
|
r.sync(syncTypeParamNames)
|
||||||
|
|
||||||
r.tparams = make([]*types2.TypeName, len(bounds))
|
// Note: This code assumes it only processes objects without
|
||||||
|
// implement type parameters. This is currently fine, because
|
||||||
|
// reader2 is only used to read in exported declarations, which are
|
||||||
|
// always package scoped.
|
||||||
|
|
||||||
for i := range r.tparams {
|
if len(r.dict.bounds) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Careful: Type parameter lists may have cycles. To allow for this,
|
||||||
|
// we construct the type parameter list in two passes: first we
|
||||||
|
// create all the TypeNames and TypeParams, then we construct and
|
||||||
|
// set the bound type.
|
||||||
|
|
||||||
|
names := make([]*types2.TypeName, len(r.dict.bounds))
|
||||||
|
r.dict.tparams = make([]*types2.TypeParam, len(r.dict.bounds))
|
||||||
|
for i := range r.dict.bounds {
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
pkg, name := r.localIdent()
|
pkg, name := r.localIdent()
|
||||||
|
|
||||||
obj := types2.NewTypeName(pos, pkg, name, nil)
|
names[i] = types2.NewTypeName(pos, pkg, name, nil)
|
||||||
r.p.check.NewTypeParam(obj, i, nil)
|
r.dict.tparams[i] = r.p.check.NewTypeParam(names[i], i, nil)
|
||||||
r.tparams[i] = obj
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tparam := range r.tparams {
|
for i, bound := range r.dict.bounds {
|
||||||
bound := r.p.typIdx(bounds[i], r.tparams)
|
var dict *reader2Dict
|
||||||
tparam.Type().(*types2.TypeParam).SetBound(bound)
|
if bound.derived {
|
||||||
|
dict = r.dict
|
||||||
}
|
}
|
||||||
|
boundType := r.p.typIdx(bound.boundIdx, dict)
|
||||||
|
r.dict.tparams[i].SetBound(boundType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader2) method(bounds []int) *types2.Func {
|
func (r *reader2) method() *types2.Func {
|
||||||
r.sync(syncMethod)
|
r.sync(syncMethod)
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
pkg, name := r.selector()
|
pkg, name := r.selector()
|
||||||
|
|
||||||
r.typeParamNames(bounds)
|
rparams := r.typeParamNames()
|
||||||
sig := r.signature(r.param())
|
sig := r.signature(r.param())
|
||||||
if len(r.tparams) != 0 {
|
sig.SetRParams(rparams)
|
||||||
sig.SetRParams(r.tparams)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
|
_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.
|
||||||
return types2.NewFunc(pos, pkg, name, sig)
|
return types2.NewFunc(pos, pkg, name, sig)
|
||||||
|
|
|
@ -34,6 +34,7 @@ const (
|
||||||
relocType
|
relocType
|
||||||
relocObj
|
relocObj
|
||||||
relocObjExt
|
relocObjExt
|
||||||
|
relocObjDict
|
||||||
relocBody
|
relocBody
|
||||||
|
|
||||||
numRelocs = iota
|
numRelocs = iota
|
||||||
|
|
|
@ -122,7 +122,7 @@ func unified(noders []*noder) {
|
||||||
|
|
||||||
// Instantiated generic function: add to Decls for typechecking
|
// Instantiated generic function: add to Decls for typechecking
|
||||||
// and compilation.
|
// and compilation.
|
||||||
if len(pri.implicits) != 0 && fn.OClosure == nil {
|
if pri.dict != nil && len(pri.dict.targs) != 0 && fn.OClosure == nil {
|
||||||
target.Decls = append(target.Decls, fn)
|
target.Decls = append(target.Decls, fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,20 +87,27 @@ type writer struct {
|
||||||
// scope closes, and then maybe we can just use the same map for
|
// scope closes, and then maybe we can just use the same map for
|
||||||
// storing the TypeParams too (as their TypeName instead).
|
// storing the TypeParams too (as their TypeName instead).
|
||||||
|
|
||||||
// type parameters. explicitIdx has the type parameters declared on
|
|
||||||
// the current object, while implicitIdx has the type parameters
|
|
||||||
// declared on the enclosing object (if any).
|
|
||||||
//
|
|
||||||
// TODO(mdempsky): Merge these back together, now that I've got them
|
|
||||||
// working.
|
|
||||||
implicitIdx map[*types2.TypeParam]int
|
|
||||||
explicitIdx map[*types2.TypeParam]int
|
|
||||||
|
|
||||||
// variables declared within this function
|
// variables declared within this function
|
||||||
localsIdx map[*types2.Var]int
|
localsIdx map[*types2.Var]int
|
||||||
|
|
||||||
closureVars []posObj
|
closureVars []posObj
|
||||||
closureVarsIdx map[*types2.Var]int
|
closureVarsIdx map[*types2.Var]int
|
||||||
|
|
||||||
|
dict *writerDict
|
||||||
|
derived bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// A writerDict tracks types and objects that are used by a declaration.
|
||||||
|
type writerDict struct {
|
||||||
|
implicits []*types2.TypeName
|
||||||
|
|
||||||
|
// derived is a slice of type indices for computing derived types
|
||||||
|
// (i.e., types that depend on the declaration's type parameters).
|
||||||
|
derived []int
|
||||||
|
|
||||||
|
// derivedIdx maps a Type to its corresponding index within the
|
||||||
|
// derived slice, if present.
|
||||||
|
derivedIdx map[types2.Type]int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pw *pkgWriter) newWriter(k reloc, marker syncMarker) *writer {
|
func (pw *pkgWriter) newWriter(k reloc, marker syncMarker) *writer {
|
||||||
|
@ -193,30 +200,39 @@ func (pw *pkgWriter) pkgIdx(pkg *types2.Package) int {
|
||||||
// @@@ Types
|
// @@@ Types
|
||||||
|
|
||||||
func (w *writer) typ(typ types2.Type) {
|
func (w *writer) typ(typ types2.Type) {
|
||||||
|
idx, derived := w.p.typIdx(typ, w.dict)
|
||||||
|
|
||||||
w.sync(syncType)
|
w.sync(syncType)
|
||||||
|
if w.bool(derived) {
|
||||||
if quirksMode() {
|
w.len(idx)
|
||||||
typ = w.p.dups.orig(typ)
|
w.derived = true
|
||||||
|
} else {
|
||||||
|
w.reloc(relocType, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.reloc(relocType, w.p.typIdx(typ, w.implicitIdx, w.explicitIdx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pw *pkgWriter) typIdx(typ types2.Type, implicitIdx, explicitIdx map[*types2.TypeParam]int) int {
|
// typIdx returns the index where the export data description of type
|
||||||
|
// can be read back in. If no such index exists yet, it's created.
|
||||||
|
//
|
||||||
|
// typIdx also reports whether typ is a derived type; that is, whether
|
||||||
|
// its identity depends on type parameters.
|
||||||
|
func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) (int, bool) {
|
||||||
|
if quirksMode() {
|
||||||
|
typ = pw.dups.orig(typ)
|
||||||
|
}
|
||||||
|
|
||||||
if idx, ok := pw.typsIdx[typ]; ok {
|
if idx, ok := pw.typsIdx[typ]; ok {
|
||||||
return idx
|
return idx, false
|
||||||
|
}
|
||||||
|
if dict != nil {
|
||||||
|
if idx, ok := dict.derivedIdx[typ]; ok {
|
||||||
|
return idx, true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
w := pw.newWriter(relocType, syncTypeIdx)
|
w := pw.newWriter(relocType, syncTypeIdx)
|
||||||
w.implicitIdx = implicitIdx
|
w.dict = dict
|
||||||
w.explicitIdx = explicitIdx
|
|
||||||
|
|
||||||
pw.typsIdx[typ] = w.idx // handle cycles
|
|
||||||
w.doTyp(typ)
|
|
||||||
return w.flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *writer) doTyp(typ types2.Type) {
|
|
||||||
switch typ := typ.(type) {
|
switch typ := typ.(type) {
|
||||||
default:
|
default:
|
||||||
base.Fatalf("unexpected type: %v (%T)", typ, typ)
|
base.Fatalf("unexpected type: %v (%T)", typ, typ)
|
||||||
|
@ -251,14 +267,19 @@ func (w *writer) doTyp(typ types2.Type) {
|
||||||
w.obj(orig.Obj(), typ.TArgs())
|
w.obj(orig.Obj(), typ.TArgs())
|
||||||
|
|
||||||
case *types2.TypeParam:
|
case *types2.TypeParam:
|
||||||
w.code(typeTypeParam)
|
index := func() int {
|
||||||
if idx, ok := w.implicitIdx[typ]; ok {
|
for idx, name := range w.dict.implicits {
|
||||||
w.len(idx)
|
if name.Type().(*types2.TypeParam) == typ {
|
||||||
} else if idx, ok := w.explicitIdx[typ]; ok {
|
return idx
|
||||||
w.len(len(w.implicitIdx) + idx)
|
|
||||||
} else {
|
|
||||||
w.p.fatalf(typ.Obj(), "%v not in %v or %v", typ, w.implicitIdx, w.explicitIdx)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(w.dict.implicits) + typ.Index()
|
||||||
|
}()
|
||||||
|
|
||||||
|
w.derived = true
|
||||||
|
w.code(typeTypeParam)
|
||||||
|
w.len(index)
|
||||||
|
|
||||||
case *types2.Array:
|
case *types2.Array:
|
||||||
w.code(typeArray)
|
w.code(typeArray)
|
||||||
|
@ -300,6 +321,16 @@ func (w *writer) doTyp(typ types2.Type) {
|
||||||
w.code(typeUnion)
|
w.code(typeUnion)
|
||||||
w.unionType(typ)
|
w.unionType(typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if w.derived {
|
||||||
|
idx := len(dict.derived)
|
||||||
|
dict.derived = append(dict.derived, w.flush())
|
||||||
|
dict.derivedIdx[typ] = idx
|
||||||
|
return idx, true
|
||||||
|
}
|
||||||
|
|
||||||
|
pw.typsIdx[typ] = w.idx
|
||||||
|
return w.flush(), false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *writer) structType(typ *types2.Struct) {
|
func (w *writer) structType(typ *types2.Struct) {
|
||||||
|
@ -367,13 +398,16 @@ func (w *writer) param(param *types2.Var) {
|
||||||
// @@@ Objects
|
// @@@ Objects
|
||||||
|
|
||||||
func (w *writer) obj(obj types2.Object, explicits []types2.Type) {
|
func (w *writer) obj(obj types2.Object, explicits []types2.Type) {
|
||||||
w.sync(syncObject)
|
if isDefinedType(obj) && obj.Pkg() == w.p.curpkg {
|
||||||
|
decl, ok := w.p.typDecls[obj.(*types2.TypeName)]
|
||||||
var implicitIdx map[*types2.TypeParam]int
|
assert(ok)
|
||||||
if isDefinedType(obj) && !isGlobal(obj) {
|
if len(decl.implicits) != 0 {
|
||||||
implicitIdx = w.implicitIdx
|
w.derived = true
|
||||||
}
|
}
|
||||||
w.reloc(relocObj, w.p.objIdx(obj, implicitIdx))
|
}
|
||||||
|
|
||||||
|
w.sync(syncObject)
|
||||||
|
w.reloc(relocObj, w.p.objIdx(obj))
|
||||||
|
|
||||||
w.len(len(explicits))
|
w.len(len(explicits))
|
||||||
for _, explicit := range explicits {
|
for _, explicit := range explicits {
|
||||||
|
@ -381,37 +415,61 @@ func (w *writer) obj(obj types2.Object, explicits []types2.Type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pw *pkgWriter) objIdx(obj types2.Object, implicitIdx map[*types2.TypeParam]int) int {
|
func (pw *pkgWriter) objIdx(obj types2.Object) int {
|
||||||
if idx, ok := pw.globalsIdx[obj]; ok {
|
if idx, ok := pw.globalsIdx[obj]; ok {
|
||||||
return idx
|
return idx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict := &writerDict{
|
||||||
|
derivedIdx: make(map[types2.Type]int),
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDefinedType(obj) && obj.Pkg() == pw.curpkg {
|
||||||
|
decl, ok := pw.typDecls[obj.(*types2.TypeName)]
|
||||||
|
assert(ok)
|
||||||
|
dict.implicits = decl.implicits
|
||||||
|
}
|
||||||
|
|
||||||
w := pw.newWriter(relocObj, syncObject1)
|
w := pw.newWriter(relocObj, syncObject1)
|
||||||
w.ext = pw.newWriter(relocObjExt, syncObject1)
|
w.ext = pw.newWriter(relocObjExt, syncObject1)
|
||||||
|
wdict := pw.newWriter(relocObjDict, syncObject1)
|
||||||
|
|
||||||
|
pw.globalsIdx[obj] = w.idx // break cycles
|
||||||
assert(w.ext.idx == w.idx)
|
assert(w.ext.idx == w.idx)
|
||||||
|
assert(wdict.idx == w.idx)
|
||||||
|
|
||||||
pw.globalsIdx[obj] = w.idx
|
w.dict = dict
|
||||||
|
w.ext.dict = dict
|
||||||
|
|
||||||
w.implicitIdx = implicitIdx
|
// Ident goes first so importer can avoid unnecessary work if
|
||||||
w.ext.implicitIdx = implicitIdx
|
// they've already resolved this object.
|
||||||
|
w.qualifiedIdent(obj)
|
||||||
|
|
||||||
|
w.typeParamBounds(objTypeParams(obj))
|
||||||
|
|
||||||
w.doObj(obj)
|
w.doObj(obj)
|
||||||
|
|
||||||
w.flush()
|
w.flush()
|
||||||
w.ext.flush()
|
w.ext.flush()
|
||||||
|
|
||||||
|
// Done writing out the object description; write out the list of
|
||||||
|
// derived types that we found along the way.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Record details about how derived types are
|
||||||
|
// actually used so reader can optimize its runtime dictionaries.
|
||||||
|
//
|
||||||
|
// TODO(mdempsky): Record details about which instantiated functions
|
||||||
|
// are used too.
|
||||||
|
wdict.len(len(dict.derived))
|
||||||
|
for _, typ := range dict.derived {
|
||||||
|
wdict.reloc(relocType, typ)
|
||||||
|
}
|
||||||
|
wdict.flush()
|
||||||
|
|
||||||
return w.idx
|
return w.idx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *writer) doObj(obj types2.Object) {
|
func (w *writer) doObj(obj types2.Object) {
|
||||||
// Ident goes first so importer can avoid unnecessary work if
|
|
||||||
// they've already resolved this object.
|
|
||||||
w.qualifiedIdent(obj)
|
|
||||||
|
|
||||||
tparams := objTypeParams(obj)
|
|
||||||
w.setTypeParams(tparams)
|
|
||||||
w.typeParamBounds(tparams)
|
|
||||||
|
|
||||||
if obj.Pkg() != w.p.curpkg {
|
if obj.Pkg() != w.p.curpkg {
|
||||||
w.code(objStub)
|
w.code(objStub)
|
||||||
return
|
return
|
||||||
|
@ -504,29 +562,12 @@ func (w *writer) value(typ types2.Type, val constant.Value) {
|
||||||
w.rawValue(val)
|
w.rawValue(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *writer) setTypeParams(tparams []*types2.TypeName) {
|
|
||||||
if len(tparams) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
explicitIdx := make(map[*types2.TypeParam]int)
|
|
||||||
for _, tparam := range tparams {
|
|
||||||
explicitIdx[tparam.Type().(*types2.TypeParam)] = len(explicitIdx)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.explicitIdx = explicitIdx
|
|
||||||
w.ext.explicitIdx = explicitIdx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *writer) typeParamBounds(tparams []*types2.TypeName) {
|
func (w *writer) typeParamBounds(tparams []*types2.TypeName) {
|
||||||
w.sync(syncTypeParamBounds)
|
w.sync(syncTypeParamBounds)
|
||||||
|
|
||||||
// TODO(mdempsky): Remove. It's useful for debugging at the moment,
|
w.len(len(w.dict.implicits))
|
||||||
// but it doesn't belong here.
|
|
||||||
w.len(len(w.implicitIdx))
|
|
||||||
w.len(len(w.explicitIdx))
|
|
||||||
assert(len(w.explicitIdx) == len(tparams))
|
|
||||||
|
|
||||||
|
w.len(len(tparams))
|
||||||
for _, tparam := range tparams {
|
for _, tparam := range tparams {
|
||||||
w.typ(tparam.Type().(*types2.TypeParam).Bound())
|
w.typ(tparam.Type().(*types2.TypeParam).Bound())
|
||||||
}
|
}
|
||||||
|
@ -546,9 +587,6 @@ func (w *writer) method(meth *types2.Func) {
|
||||||
assert(ok)
|
assert(ok)
|
||||||
sig := meth.Type().(*types2.Signature)
|
sig := meth.Type().(*types2.Signature)
|
||||||
|
|
||||||
assert(len(w.explicitIdx) == len(sig.RParams()))
|
|
||||||
w.setTypeParams(sig.RParams())
|
|
||||||
|
|
||||||
w.sync(syncMethod)
|
w.sync(syncMethod)
|
||||||
w.pos(meth)
|
w.pos(meth)
|
||||||
w.selector(meth)
|
w.selector(meth)
|
||||||
|
@ -566,12 +604,15 @@ func (w *writer) qualifiedIdent(obj types2.Object) {
|
||||||
w.sync(syncSym)
|
w.sync(syncSym)
|
||||||
|
|
||||||
name := obj.Name()
|
name := obj.Name()
|
||||||
if isDefinedType(obj) && !isGlobal(obj) {
|
if isDefinedType(obj) && obj.Pkg() == w.p.curpkg {
|
||||||
// TODO(mdempsky): Find a better solution, this is terrible.
|
|
||||||
decl, ok := w.p.typDecls[obj.(*types2.TypeName)]
|
decl, ok := w.p.typDecls[obj.(*types2.TypeName)]
|
||||||
assert(ok)
|
assert(ok)
|
||||||
|
if decl.gen != 0 {
|
||||||
|
// TODO(mdempsky): Find a better solution than embedding middle
|
||||||
|
// dot in the symbol name; this is terrible.
|
||||||
name = fmt.Sprintf("%s·%v", name, decl.gen)
|
name = fmt.Sprintf("%s·%v", name, decl.gen)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
w.pkg(obj.Pkg())
|
w.pkg(obj.Pkg())
|
||||||
w.string(name)
|
w.string(name)
|
||||||
|
@ -630,7 +671,7 @@ func (w *writer) funcExt(obj *types2.Func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sig, block := obj.Type().(*types2.Signature), decl.Body
|
sig, block := obj.Type().(*types2.Signature), decl.Body
|
||||||
body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.explicitIdx)
|
body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.dict)
|
||||||
assert(len(closureVars) == 0)
|
assert(len(closureVars) == 0)
|
||||||
|
|
||||||
w.sync(syncFuncExt)
|
w.sync(syncFuncExt)
|
||||||
|
@ -672,9 +713,9 @@ func (w *writer) pragmaFlag(p ir.PragmaFlag) {
|
||||||
|
|
||||||
// @@@ Function bodies
|
// @@@ Function bodies
|
||||||
|
|
||||||
func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, implicitIdx map[*types2.TypeParam]int) (idx int, closureVars []posObj) {
|
func (pw *pkgWriter) bodyIdx(pkg *types2.Package, sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx int, closureVars []posObj) {
|
||||||
w := pw.newWriter(relocBody, syncFuncBody)
|
w := pw.newWriter(relocBody, syncFuncBody)
|
||||||
w.implicitIdx = implicitIdx
|
w.dict = dict
|
||||||
|
|
||||||
w.funcargs(sig)
|
w.funcargs(sig)
|
||||||
if w.bool(block != nil) {
|
if w.bool(block != nil) {
|
||||||
|
@ -1238,14 +1279,13 @@ func (w *writer) funcLit(expr *syntax.FuncLit) {
|
||||||
assert(ok)
|
assert(ok)
|
||||||
sig := tv.Type.(*types2.Signature)
|
sig := tv.Type.(*types2.Signature)
|
||||||
|
|
||||||
|
body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, expr.Body, w.dict)
|
||||||
|
|
||||||
w.sync(syncFuncLit)
|
w.sync(syncFuncLit)
|
||||||
w.pos(expr)
|
w.pos(expr)
|
||||||
w.pos(expr.Type) // for QuirksMode
|
w.pos(expr.Type) // for QuirksMode
|
||||||
w.signature(sig)
|
w.signature(sig)
|
||||||
|
|
||||||
block := expr.Body
|
|
||||||
body, closureVars := w.p.bodyIdx(w.p.curpkg, sig, block, w.implicitIdx)
|
|
||||||
|
|
||||||
w.len(len(closureVars))
|
w.len(len(closureVars))
|
||||||
for _, cv := range closureVars {
|
for _, cv := range closureVars {
|
||||||
w.pos(cv.pos)
|
w.pos(cv.pos)
|
||||||
|
@ -1297,6 +1337,9 @@ func (w *writer) op(op ir.Op) {
|
||||||
type typeDeclGen struct {
|
type typeDeclGen struct {
|
||||||
*syntax.TypeDecl
|
*syntax.TypeDecl
|
||||||
gen int
|
gen int
|
||||||
|
|
||||||
|
// Implicit type parameters in scope at this type declaration.
|
||||||
|
implicits []*types2.TypeName
|
||||||
}
|
}
|
||||||
|
|
||||||
type fileImports struct {
|
type fileImports struct {
|
||||||
|
@ -1308,6 +1351,19 @@ type declCollector struct {
|
||||||
typegen *int
|
typegen *int
|
||||||
file *fileImports
|
file *fileImports
|
||||||
withinFunc bool
|
withinFunc bool
|
||||||
|
implicits []*types2.TypeName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *declCollector) withTParams(obj types2.Object) *declCollector {
|
||||||
|
tparams := objTypeParams(obj)
|
||||||
|
if len(tparams) == 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
copy := *c
|
||||||
|
copy.implicits = copy.implicits[:len(copy.implicits):len(copy.implicits)]
|
||||||
|
copy.implicits = append(copy.implicits, objTypeParams(obj)...)
|
||||||
|
return ©
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
|
func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
|
||||||
|
@ -1336,9 +1392,11 @@ func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
|
||||||
obj := pw.info.Defs[n.Name].(*types2.Func)
|
obj := pw.info.Defs[n.Name].(*types2.Func)
|
||||||
pw.funDecls[obj] = n
|
pw.funDecls[obj] = n
|
||||||
|
|
||||||
|
return c.withTParams(obj)
|
||||||
|
|
||||||
case *syntax.TypeDecl:
|
case *syntax.TypeDecl:
|
||||||
obj := pw.info.Defs[n.Name].(*types2.TypeName)
|
obj := pw.info.Defs[n.Name].(*types2.TypeName)
|
||||||
d := typeDeclGen{TypeDecl: n}
|
d := typeDeclGen{TypeDecl: n, implicits: c.implicits}
|
||||||
|
|
||||||
if n.Alias {
|
if n.Alias {
|
||||||
pw.checkPragmas(n.Pragma, 0, false)
|
pw.checkPragmas(n.Pragma, 0, false)
|
||||||
|
@ -1346,7 +1404,7 @@ func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
|
||||||
pw.checkPragmas(n.Pragma, typePragmas, false)
|
pw.checkPragmas(n.Pragma, typePragmas, false)
|
||||||
|
|
||||||
// Assign a unique ID to function-scoped defined types.
|
// Assign a unique ID to function-scoped defined types.
|
||||||
if !isGlobal(obj) {
|
if c.withinFunc {
|
||||||
*c.typegen++
|
*c.typegen++
|
||||||
d.gen = *c.typegen
|
d.gen = *c.typegen
|
||||||
}
|
}
|
||||||
|
@ -1354,6 +1412,12 @@ func (c *declCollector) Visit(n syntax.Node) syntax.Visitor {
|
||||||
|
|
||||||
pw.typDecls[obj] = d
|
pw.typDecls[obj] = d
|
||||||
|
|
||||||
|
// TODO(mdempsky): Omit? Not strictly necessary; only matters for
|
||||||
|
// type declarations within function literals within parameterized
|
||||||
|
// type declarations, but types2 the function literals will be
|
||||||
|
// constant folded away.
|
||||||
|
return c.withTParams(obj)
|
||||||
|
|
||||||
case *syntax.VarDecl:
|
case *syntax.VarDecl:
|
||||||
pw.checkPragmas(n.Pragma, 0, true)
|
pw.checkPragmas(n.Pragma, 0, true)
|
||||||
|
|
||||||
|
@ -1510,8 +1574,11 @@ func (w *writer) pkgDecl(decl syntax.Decl) {
|
||||||
break // skip generic type decls
|
break // skip generic type decls
|
||||||
}
|
}
|
||||||
|
|
||||||
name := w.p.info.Defs[decl.Name].(*types2.TypeName)
|
if decl.Name.Value == "_" {
|
||||||
|
break // skip blank type decls
|
||||||
|
}
|
||||||
|
|
||||||
|
name := w.p.info.Defs[decl.Name].(*types2.TypeName)
|
||||||
// Skip type declarations for interfaces that are only usable as
|
// Skip type declarations for interfaces that are only usable as
|
||||||
// type parameter bounds.
|
// type parameter bounds.
|
||||||
if iface, ok := name.Type().Underlying().(*types2.Interface); ok && iface.IsConstraint() {
|
if iface, ok := name.Type().Underlying().(*types2.Interface); ok && iface.IsConstraint() {
|
||||||
|
@ -1671,7 +1738,11 @@ func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int {
|
||||||
func objTypeParams(obj types2.Object) []*types2.TypeName {
|
func objTypeParams(obj types2.Object) []*types2.TypeName {
|
||||||
switch obj := obj.(type) {
|
switch obj := obj.(type) {
|
||||||
case *types2.Func:
|
case *types2.Func:
|
||||||
return obj.Type().(*types2.Signature).TParams()
|
sig := obj.Type().(*types2.Signature)
|
||||||
|
if sig.Recv() != nil {
|
||||||
|
return sig.RParams()
|
||||||
|
}
|
||||||
|
return sig.TParams()
|
||||||
case *types2.TypeName:
|
case *types2.TypeName:
|
||||||
if !obj.IsAlias() {
|
if !obj.IsAlias() {
|
||||||
return obj.Type().(*types2.Named).TParams()
|
return obj.Type().(*types2.Named).TParams()
|
||||||
|
|
Loading…
Reference in a new issue