Skip to content

[generics] Fixed collecting instances from inverted dependencies #1384

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions compiler/decls.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,23 @@ type Decl struct {
TypeDeclCode []byte
// JavaScript code that assigns exposed named types to the package.
ExportTypeCode []byte
// JavaScript code that declares basic information about an anonymous types.
// JavaScript code that declares basic information about an anonymous type.
// It configures basic information about the type.
// This is added to the finish setup phase to has access to all packages.
// This is added to the finish setup phase to have access to all packages.
AnonTypeDeclCode []byte
// JavaScript code that declares basic information about a function or
// method symbol. This contains the function's or method's compiled body.
// This is added to the finish setup phase to has access to all packages.
// This is added to the finish setup phase to have access to all packages.
FuncDeclCode []byte
// JavaScript code that assigns exposed functions to the package.
// This is added to the finish setup phase to has access to all packages.
// This is added to the finish setup phase to have access to all packages.
ExportFuncCode []byte
// JavaScript code that initializes reflection metadata about type's method list.
// This is added to the finish setup phase to has access to all packages.
// JavaScript code that initializes reflection metadata about a type's method list.
// This is added to the finish setup phase to have access to all packages.
MethodListCode []byte
// JavaScript code that initializes the rest of reflection metadata about a type
// (e.g. struct fields, array type sizes, element types, etc.).
// This is added to the finish setup phase to has access to all packages.
// This is added to the finish setup phase to have access to all packages.
TypeInitCode []byte
// JavaScript code that needs to be executed during the package init phase to
// set the symbol up (e.g. initialize package-level variable value).
Expand Down
10 changes: 5 additions & 5 deletions compiler/internal/analysis/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1632,13 +1632,13 @@ func newBlockingTest(t *testing.T, src string) *blockingTest {
tContext := types.NewContext()
tc := typeparams.Collector{
TContext: tContext,
Info: f.Info,
Instances: &typeparams.PackageInstanceSets{},
}

file := f.Parse(`test.go`, src)
testInfo, testPkg := f.Check(`pkg/test`, file)
tc.Scan(testPkg, file)
tc.Scan(testInfo, testPkg, file)
tc.Finish()

getImportInfo := func(path string) (*Info, error) {
return nil, fmt.Errorf(`getImportInfo should not be called in this test, called with %v`, path)
Expand All @@ -1658,7 +1658,6 @@ func newBlockingTestWithOtherPackage(t *testing.T, testSrc string, otherSrc stri
tContext := types.NewContext()
tc := typeparams.Collector{
TContext: tContext,
Info: f.Info,
Instances: &typeparams.PackageInstanceSets{},
}

Expand All @@ -1672,11 +1671,12 @@ func newBlockingTestWithOtherPackage(t *testing.T, testSrc string, otherSrc stri

otherFile := f.Parse(`other.go`, otherSrc)
_, otherPkg := f.Check(`pkg/other`, otherFile)
tc.Scan(otherPkg, otherFile)
tc.Scan(f.Info, otherPkg, otherFile)

testFile := f.Parse(`test.go`, testSrc)
_, testPkg := f.Check(`pkg/test`, testFile)
tc.Scan(testPkg, testFile)
tc.Scan(f.Info, testPkg, testFile)
tc.Finish()

otherPkgInfo := AnalyzePkg([]*ast.File{otherFile}, f.FileSet, f.Info, tContext, otherPkg, tc.Instances, getImportInfo)
pkgInfo[otherPkg.Path()] = otherPkgInfo
Expand Down
56 changes: 41 additions & 15 deletions compiler/internal/typeparams/collect.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,59 +188,85 @@ func (c *seedVisitor) Visit(n ast.Node) ast.Visitor {
// set whenever their receiver type instance is encountered.
type Collector struct {
TContext *types.Context
Info *types.Info
Instances *PackageInstanceSets

objMap map[types.Object]ast.Node
infoMap map[string]*types.Info
}

// Scan package files for generic instances.
func (c *Collector) Scan(pkg *types.Package, files ...*ast.File) {
if c.Info.Instances == nil || c.Info.Defs == nil {
func (c *Collector) Scan(info *types.Info, pkg *types.Package, files ...*ast.File) {
if c.objMap == nil {
c.objMap = map[types.Object]ast.Node{}
}
if c.infoMap == nil {
c.infoMap = map[string]*types.Info{}
}

// Check the info for this package then record it for later use.
if info.Instances == nil || info.Defs == nil {
panic(fmt.Errorf("types.Info must have Instances and Defs populated"))
}
objMap := map[types.Object]ast.Node{}
c.infoMap[pkg.Path()] = info

// Collect instances of generic objects in non-generic code in the package and
// add then to the existing InstanceSet.
sc := seedVisitor{
visitor: visitor{
instances: c.Instances,
resolver: nil,
info: c.Info,
info: info,
},
objMap: objMap,
objMap: c.objMap,
}
for _, file := range files {
ast.Walk(&sc, file)
}
}

// Finish will finish the collecting instances by propagating instances of
// generic types and functions found in generic code. The generic code is
// rescanned with in an instances context to find internally defined instances.
//
// This should only be called after all the files are scanned.
func (c *Collector) Finish() {
for !c.Instances.allExhausted() {
for pkgPath, instances := range *c.Instances {
c.propagate(pkgPath, instances)
}
}
}

for iset := c.Instances.Pkg(pkg); !iset.exhausted(); {
func (c *Collector) propagate(pkgPath string, instances *InstanceSet) {
info := c.infoMap[pkgPath]
for iset := instances; !iset.exhausted(); {
inst, _ := iset.next()

switch typ := inst.Object.Type().(type) {
case *types.Signature:
c.scanSignature(inst, typ, objMap)
c.scanSignature(inst, typ, info)

case *types.Named:
c.scanNamed(inst, typ, objMap)
c.scanNamed(inst, typ, info)
}
}
}

func (c *Collector) scanSignature(inst Instance, typ *types.Signature, objMap map[types.Object]ast.Node) {
func (c *Collector) scanSignature(inst Instance, typ *types.Signature, info *types.Info) {
v := visitor{
instances: c.Instances,
resolver: NewResolver(c.TContext, inst),
info: c.Info,
info: info,

nestTParams: SignatureTypeParams(typ),
nestTArgs: inst.TArgs,
}
ast.Walk(&v, objMap[inst.Object])
ast.Walk(&v, c.objMap[inst.Object])
}

func (c *Collector) scanNamed(inst Instance, typ *types.Named, objMap map[types.Object]ast.Node) {
func (c *Collector) scanNamed(inst Instance, typ *types.Named, info *types.Info) {
obj := typ.Obj()
node := objMap[obj]
node := c.objMap[obj]
if node == nil {
// Types without an entry in objMap are concrete types
// that are defined in a generic context. Skip them.
Expand All @@ -256,7 +282,7 @@ func (c *Collector) scanNamed(inst Instance, typ *types.Named, objMap map[types.
v := visitor{
instances: c.Instances,
resolver: NewResolver(c.TContext, inst),
info: c.Info,
info: info,

nestTParams: nestTParams,
nestTArgs: inst.TNest,
Expand Down
Loading
Loading