aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMark Freeman <mark@golang.org>2026-04-06 12:33:16 -0400
committerMark Freeman <mark@golang.org>2026-04-06 11:50:01 -0700
commita91083291cd7ea07cd766b7c71b889f476cf3084 (patch)
treefcc022fe5d80984dd2dc155151155ccaa7dc0f9d /src
parent24596d3243ba0a9d855d1ede30245ba00d7f1962 (diff)
downloadgo-a91083291cd7ea07cd766b7c71b889f476cf3084.tar.xz
go/internal/gcimporter: consume generic methods in gcimporter
Change-Id: I32af8f18da6c9c95d6fe6189d2f6735868667b3e Reviewed-on: https://go-review.googlesource.com/c/go/+/763120 Auto-Submit: Mark Freeman <markfreeman@google.com> Reviewed-by: Robert Griesemer <gri@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src')
-rw-r--r--src/go/internal/gcimporter/ureader.go103
1 files changed, 66 insertions, 37 deletions
diff --git a/src/go/internal/gcimporter/ureader.go b/src/go/internal/gcimporter/ureader.go
index 79ac636dcd..741140c0c0 100644
--- a/src/go/internal/gcimporter/ureader.go
+++ b/src/go/internal/gcimporter/ureader.go
@@ -30,6 +30,10 @@ type pkgReader struct {
// laterFns holds functions that need to be invoked at the end of
// import reading.
+ //
+ // TODO(mdempsky): Is it safe to have a single "later" slice or do
+ // we need to have multiple passes? See comments on CL 386002 and
+ // go.dev/issue/52104.
laterFns []func()
// ifaces holds a list of constructed Interfaces, which need to have
@@ -118,12 +122,11 @@ type reader struct {
// A readerDict holds the state for type parameters that parameterize
// the current unified IR element.
type readerDict struct {
- // bounds is a slice of typeInfos corresponding to the underlying
- // bounds of the element's type parameters.
- bounds []typeInfo
+ rtbounds []typeInfo // contains constraint types for each parameter in rtparams
+ rtparams []*types.TypeParam // contains receiver type parameters for an element
- // tparams is a slice of the constructed TypeParams for the element.
- tparams []*types.TypeParam
+ tbounds []typeInfo // contains constraint types for each parameter in tparams
+ tparams []*types.TypeParam // contains type parameters for an element
// derived is a slice of types derived from tparams, which may be
// instantiated while reading the current element.
@@ -308,7 +311,11 @@ func (r *reader) doTyp() (res types.Type) {
return name.Type()
case pkgbits.TypeTypeParam:
- return r.dict.tparams[r.Len()]
+ n := r.Len()
+ if n < len(r.dict.rtbounds) {
+ return r.dict.rtparams[n]
+ }
+ return r.dict.tparams[n-len(r.dict.rtbounds)]
case pkgbits.TypeArray:
len := int64(r.Uint64())
@@ -491,7 +498,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
pos := r.pos()
var tparams []*types.TypeParam
if r.Version().Has(pkgbits.AliasTypeParamNames) {
- tparams = r.typeParamNames()
+ tparams = r.typeParamNames(false)
}
typ := r.typ()
declare(newAliasTypeName(pos, objPkg, objName, typ, tparams))
@@ -504,8 +511,15 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
case pkgbits.ObjFunc:
pos := r.pos()
- tparams := r.typeParamNames()
- sig := r.signature(nil, nil, tparams)
+ var rtparams []*types.TypeParam
+ var recv *types.Var
+ if r.Version().Has(pkgbits.GenericMethods) && r.Bool() {
+ r.selector()
+ rtparams = r.typeParamNames(true)
+ recv = r.param(types.RecvVar)
+ }
+ tparams := r.typeParamNames(false)
+ sig := r.signature(recv, rtparams, tparams)
declare(types.NewFunc(pos, objPkg, objName, sig))
case pkgbits.ObjType:
@@ -515,7 +529,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
named := types.NewNamed(obj, nil, nil)
declare(obj)
- named.SetTypeParams(r.typeParamNames())
+ named.SetTypeParams(r.typeParamNames(false))
underlying := r.typ().Underlying()
@@ -569,9 +583,20 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
errorf("unexpected object with %v implicit type parameter(s)", implicits)
}
- dict.bounds = make([]typeInfo, r.Len())
- for i := range dict.bounds {
- dict.bounds[i] = r.typInfo()
+ nreceivers := 0
+ if r.Version().Has(pkgbits.GenericMethods) && r.Bool() {
+ nreceivers = r.Len()
+ }
+ nexplicits := r.Len()
+
+ dict.rtbounds = make([]typeInfo, nreceivers)
+ for i := range dict.rtbounds {
+ dict.rtbounds[i] = r.typInfo()
+ }
+
+ dict.tbounds = make([]typeInfo, nexplicits)
+ for i := range dict.tbounds {
+ dict.tbounds[i] = r.typInfo()
}
dict.derived = make([]derivedInfo, r.Len())
@@ -590,14 +615,24 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
return &dict
}
-func (r *reader) typeParamNames() []*types.TypeParam {
+func (r *reader) typeParamNames(isGenMeth bool) []*types.TypeParam {
r.Sync(pkgbits.SyncTypeParamNames)
// Note: This code assumes there are no implicit type parameters.
// This is fine since it only reads exported declarations, which
// never have implicits.
- if len(r.dict.bounds) == 0 {
+ var in []typeInfo
+ var out *[]*types.TypeParam
+ if isGenMeth {
+ in = r.dict.rtbounds
+ out = &r.dict.rtparams
+ } else {
+ in = r.dict.tbounds
+ out = &r.dict.tparams
+ }
+
+ if len(in) == 0 {
return nil
}
@@ -606,40 +641,34 @@ func (r *reader) typeParamNames() []*types.TypeParam {
// create all the TypeNames and TypeParams, then we construct and
// set the bound type.
- r.dict.tparams = make([]*types.TypeParam, len(r.dict.bounds))
- for i := range r.dict.bounds {
+ // We have to save tparams outside of the closure, because typeParamNames
+ // can be called multiple times with the same dictionary instance.
+ tparams := make([]*types.TypeParam, len(in))
+ *out = tparams
+
+ for i := range in {
pos := r.pos()
pkg, name := r.localIdent()
tname := types.NewTypeName(pos, pkg, name, nil)
- r.dict.tparams[i] = types.NewTypeParam(tname, nil)
+ tparams[i] = types.NewTypeParam(tname, nil)
}
- typs := make([]types.Type, len(r.dict.bounds))
- for i, bound := range r.dict.bounds {
- typs[i] = r.p.typIdx(bound, r.dict)
+ // The reader dictionary will continue mutating before we have time
+ // to call delayed functions; make a local copy of the constraints.
+ types := make([]types.Type, len(in))
+ for i, info := range in {
+ types[i] = r.p.typIdx(info, r.dict)
}
- // TODO(mdempsky): This is subtle, elaborate further.
- //
- // We have to save tparams outside of the closure, because
- // typeParamNames() can be called multiple times with the same
- // dictionary instance.
- //
- // Also, this needs to happen later to make sure SetUnderlying has
- // been called.
- //
- // TODO(mdempsky): Is it safe to have a single "later" slice or do
- // we need to have multiple passes? See comments on CL 386002 and
- // go.dev/issue/52104.
- tparams := r.dict.tparams
+ // This needs to happen later to make sure SetUnderlying has been called.
r.p.later(func() {
- for i, typ := range typs {
+ for i, typ := range types {
tparams[i].SetConstraint(typ)
}
})
- return r.dict.tparams
+ return tparams
}
func (r *reader) method() *types.Func {
@@ -647,7 +676,7 @@ func (r *reader) method() *types.Func {
pos := r.pos()
pkg, name := r.selector()
- rparams := r.typeParamNames()
+ rparams := r.typeParamNames(false)
sig := r.signature(r.param(types.RecvVar), rparams, nil)
_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.