Skip to content

Commit f6476fb

Browse files
committed
internal/gcimporter: consume generic methods in gcimporter
This is a copy of CL 763120 for x/tools. Change-Id: I49008d3c78f8b4dadc93502a70becb8ad097128d Reviewed-on: https://go-review.googlesource.com/c/tools/+/763663 Reviewed-by: Robert Griesemer <gri@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent b36d1d1 commit f6476fb

1 file changed

Lines changed: 69 additions & 41 deletions

File tree

internal/gcimporter/ureader_yes.go

Lines changed: 69 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ type pkgReader struct {
3535

3636
// laterFns holds functions that need to be invoked at the end of
3737
// import reading.
38+
//
39+
// TODO(mdempsky): Is it safe to have a single "later" slice or do
40+
// we need to have multiple passes? See comments on CL 386002 and
41+
// go.dev/issue/52104.
3842
laterFns []func()
3943
// laterFors is used in case of 'type A B' to ensure that B is processed before A.
4044
laterFors map[types.Type]int
@@ -158,12 +162,11 @@ type reader struct {
158162
// A readerDict holds the state for type parameters that parameterize
159163
// the current unified IR element.
160164
type readerDict struct {
161-
// bounds is a slice of typeInfos corresponding to the underlying
162-
// bounds of the element's type parameters.
163-
bounds []typeInfo
165+
rtbounds []typeInfo // contains constraint types for each parameter in rtparams
166+
rtparams []*types.TypeParam // contains receiver type parameters for an element
164167

165-
// tparams is a slice of the constructed TypeParams for the element.
166-
tparams []*types.TypeParam
168+
tbounds []typeInfo // contains constraint types for each parameter in tparams
169+
tparams []*types.TypeParam // contains type parameters for an element
167170

168171
// derived is a slice of types derived from tparams, which may be
169172
// instantiated while reading the current element.
@@ -353,7 +356,11 @@ func (r *reader) doTyp() (res types.Type) {
353356
return name.Type()
354357

355358
case pkgbits.TypeTypeParam:
356-
return r.dict.tparams[r.Len()]
359+
n := r.Len()
360+
if n < len(r.dict.rtbounds) {
361+
return r.dict.rtparams[n]
362+
}
363+
return r.dict.tparams[n-len(r.dict.rtbounds)]
357364

358365
case pkgbits.TypeArray:
359366
len := int64(r.Uint64())
@@ -534,7 +541,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
534541
pos := r.pos()
535542
var tparams []*types.TypeParam
536543
if r.Version().Has(pkgbits.AliasTypeParamNames) {
537-
tparams = r.typeParamNames()
544+
tparams = r.typeParamNames(false)
538545
}
539546
typ := r.typ()
540547
declare(aliases.New(pos, objPkg, objName, typ, tparams))
@@ -547,8 +554,15 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
547554

548555
case pkgbits.ObjFunc:
549556
pos := r.pos()
550-
tparams := r.typeParamNames()
551-
sig := r.signature(nil, nil, tparams)
557+
var rtparams []*types.TypeParam
558+
var recv *types.Var
559+
if r.Version().Has(pkgbits.GenericMethods) && r.Bool() {
560+
r.selector()
561+
rtparams = r.typeParamNames(true)
562+
recv = r.param()
563+
}
564+
tparams := r.typeParamNames(false)
565+
sig := r.signature(recv, rtparams, tparams)
552566
declare(types.NewFunc(pos, objPkg, objName, sig))
553567

554568
case pkgbits.ObjType:
@@ -558,7 +572,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
558572
named := types.NewNamed(obj, nil, nil)
559573
declare(obj)
560574

561-
named.SetTypeParams(r.typeParamNames())
575+
named.SetTypeParams(r.typeParamNames(false))
562576

563577
setUnderlying := func(underlying types.Type) {
564578
// If the underlying type is an interface, we need to
@@ -638,9 +652,20 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
638652
errorf("unexpected object with %v implicit type parameter(s)", implicits)
639653
}
640654

641-
dict.bounds = make([]typeInfo, r.Len())
642-
for i := range dict.bounds {
643-
dict.bounds[i] = r.typInfo()
655+
nreceivers := 0
656+
if r.Version().Has(pkgbits.GenericMethods) && r.Bool() {
657+
nreceivers = r.Len()
658+
}
659+
nexplicits := r.Len()
660+
661+
dict.rtbounds = make([]typeInfo, nreceivers)
662+
for i := range dict.rtbounds {
663+
dict.rtbounds[i] = r.typInfo()
664+
}
665+
666+
dict.tbounds = make([]typeInfo, nexplicits)
667+
for i := range dict.tbounds {
668+
dict.tbounds[i] = r.typInfo()
644669
}
645670

646671
dict.derived = make([]derivedInfo, r.Len())
@@ -659,15 +684,24 @@ func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict {
659684
return &dict
660685
}
661686

662-
func (r *reader) typeParamNames() []*types.TypeParam {
687+
func (r *reader) typeParamNames(isGenMeth bool) []*types.TypeParam {
663688
r.Sync(pkgbits.SyncTypeParamNames)
664689

665-
// Note: This code assumes it only processes objects without
666-
// implement type parameters. This is currently fine, because
667-
// reader is only used to read in exported declarations, which are
668-
// always package scoped.
690+
// Note: This code assumes there are no implicit type parameters.
691+
// This is fine since it only reads exported declarations, which
692+
// never have implicits.
669693

670-
if len(r.dict.bounds) == 0 {
694+
var in []typeInfo
695+
var out *[]*types.TypeParam
696+
if isGenMeth {
697+
in = r.dict.rtbounds
698+
out = &r.dict.rtparams
699+
} else {
700+
in = r.dict.tbounds
701+
out = &r.dict.tparams
702+
}
703+
704+
if len(in) == 0 {
671705
return nil
672706
}
673707

@@ -676,48 +710,42 @@ func (r *reader) typeParamNames() []*types.TypeParam {
676710
// create all the TypeNames and TypeParams, then we construct and
677711
// set the bound type.
678712

679-
r.dict.tparams = make([]*types.TypeParam, len(r.dict.bounds))
680-
for i := range r.dict.bounds {
713+
// We have to save tparams outside of the closure, because typeParamNames
714+
// can be called multiple times with the same dictionary instance.
715+
tparams := make([]*types.TypeParam, len(in))
716+
*out = tparams
717+
718+
for i := range in {
681719
pos := r.pos()
682720
pkg, name := r.localIdent()
683721

684722
tname := types.NewTypeName(pos, pkg, name, nil)
685-
r.dict.tparams[i] = types.NewTypeParam(tname, nil)
723+
tparams[i] = types.NewTypeParam(tname, nil)
686724
}
687725

688-
typs := make([]types.Type, len(r.dict.bounds))
689-
for i, bound := range r.dict.bounds {
690-
typs[i] = r.p.typIdx(bound, r.dict)
726+
// The reader dictionary will continue mutating before we have time
727+
// to call delayed functions; make a local copy of the constraints.
728+
types := make([]types.Type, len(in))
729+
for i, info := range in {
730+
types[i] = r.p.typIdx(info, r.dict)
691731
}
692732

693-
// TODO(mdempsky): This is subtle, elaborate further.
694-
//
695-
// We have to save tparams outside of the closure, because
696-
// typeParamNames() can be called multiple times with the same
697-
// dictionary instance.
698-
//
699-
// Also, this needs to happen later to make sure SetUnderlying has
700-
// been called.
701-
//
702-
// TODO(mdempsky): Is it safe to have a single "later" slice or do
703-
// we need to have multiple passes? See comments on CL 386002 and
704-
// go.dev/issue/52104.
705-
tparams := r.dict.tparams
733+
// This needs to happen later to make sure SetUnderlying has been called.
706734
r.p.later(func() {
707-
for i, typ := range typs {
735+
for i, typ := range types {
708736
tparams[i].SetConstraint(typ)
709737
}
710738
})
711739

712-
return r.dict.tparams
740+
return tparams
713741
}
714742

715743
func (r *reader) method() *types.Func {
716744
r.Sync(pkgbits.SyncMethod)
717745
pos := r.pos()
718746
pkg, name := r.selector()
719747

720-
rparams := r.typeParamNames()
748+
rparams := r.typeParamNames(false)
721749
sig := r.signature(r.param(), rparams, nil)
722750

723751
_ = r.pos() // TODO(mdempsky): Remove; this is a hacker for linker.go.

0 commit comments

Comments
 (0)