Skip to content

Commit

Permalink
add test case to verify creating pkg after building program
Browse files Browse the repository at this point in the history
  • Loading branch information
xieyuschen committed Sep 13, 2024
1 parent 7518934 commit c058a06
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 2 deletions.
1 change: 0 additions & 1 deletion go/ssa/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3178,7 +3178,6 @@ func (p *Package) build() {
p.created = nil
p.files = nil
p.initVersion = nil
p.ninit = 0

if p.Prog.mode&SanityCheckFunctions != 0 {
sanityCheckPackage(p)
Expand Down
2 changes: 1 addition & 1 deletion go/ssa/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func (prog *Program) CreatePackage(pkg *types.Package, files []*ast.File, info *
panic("nil pkg") // otherwise pkg.Scope below returns types.Universe!
}

prog.ensurePackagesUnbuild()
// prog.ensurePackagesUnbuild()

p := &Package{
Prog: prog,
Expand Down
216 changes: 216 additions & 0 deletions go/ssa/instantiate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,48 @@ import (
"golang.org/x/tools/go/loader"
)

// loadProgram creates loader.Program out of p.
func loadProgramWith2Pkgs(p, p2 string) (*loader.Program, error) {
// Parse
var conf loader.Config
f, err := conf.ParseFile("<input>", p)
if err != nil {
return nil, fmt.Errorf("parse: %v", err)
}
conf.CreateFromFiles("p", f)

f2, err := conf.ParseFile("<input>", p2)
if err != nil {
return nil, fmt.Errorf("parse: %v", err)
}
conf.CreateFromFiles("p2", f2)

// Load
lprog, err := conf.Load()
if err != nil {
return nil, fmt.Errorf("Load: %v", err)
}
return lprog, nil
}

// loadProgram creates loader.Program out of p.
func loadProgram2(p string) (*loader.Program, error) {
// Parse
var conf loader.Config
f, err := conf.ParseFile("<input>", p)
if err != nil {
return nil, fmt.Errorf("parse: %v", err)
}
conf.CreateFromFiles("p2", f)

// Load
lprog, err := conf.Load()
if err != nil {
return nil, fmt.Errorf("Load: %v", err)
}
return lprog, nil
}

// loadProgram creates loader.Program out of p.
func loadProgram(p string) (*loader.Program, error) {
// Parse
Expand Down Expand Up @@ -49,6 +91,180 @@ func buildPackage(lprog *loader.Program, pkg string, mode BuilderMode) *Package
return p
}

func TestCreateNewPkgsFromTwoLoads(t *testing.T) {
const input = `
package p
import "slices"
func main(){
ints := []int{1, 2, 3, 4, 5}
slices.Contains(ints, 1)
}
`
const input2 = `
package p2
import "slices"
func Entry(){
numbers := []float32{1, 2, 3, 4, 5}
slices.Contains(numbers, 1)
}
`

lprog, err := loadProgram(input)
if err != nil {
t.Fatal(err)
}

mode := InstantiateGenerics
p := buildPackage(lprog, "p", mode)
prog := p.Prog
prog.Build()

lprog2, err := loadProgram(input2)
if err != nil {
t.Fatal(err)
}

var info *loader.PackageInfo
for tp, i := range lprog2.AllPackages {
if tp.Name() == "p2" {
info = i
}
}

npkg := prog.CreatePackage(info.Pkg, info.Files, &info.Info, info.Importable)

var panicked bool
func() {
defer func() {
if recover() != nil {
panicked = true
}
}()
npkg.Build()
}()

if !panicked {
t.Fatal("add a pkg loaded in another turn should panic")
}
}

func TestCreateNewPkgs(t *testing.T) {
const input = `
package p
import "slices"
func main(){
ints := []int{1, 2, 3, 4, 5}
slices.Contains(ints, 1)
}
`
const input2 = `
package p2
import "slices"
func Entry(){
numbers := []float32{1, 2, 3, 4, 5}
slices.Contains(numbers, 1)
}
`

lprog, err := loadProgramWith2Pkgs(input, input2)
if err != nil {
t.Fatal(err)
}

mode := InstantiateGenerics
p := buildPackage(lprog, "p", mode)
prog := p.Prog
prog.Build()

var slicesPkg *Package
for _, pkg := range prog.AllPackages() {
if pkg.Pkg.Name() == "slices" {
slicesPkg = pkg
break
}
}

slicesPkg.Func("Contains").generic.instancesMu.Lock()
instanceNum := len(slicesPkg.Func("Contains").generic.instances)
t.Log(slicesPkg.Func("Contains").generic.instances)
if instanceNum != 2 {
// here, we hope we can get 2 instances
t.Errorf("slices.Contains should have 2 instances but got %d", instanceNum)
}
slicesPkg.Func("Contains").generic.instancesMu.Unlock()
}

func TestCreateNewPkgAfterBuild(t *testing.T) {
const input = `
package p
import "slices"
func main(){
ints := []int{1, 2, 3, 4, 5}
slices.Contains(ints, 1)
}
`
const input2 = `
package p2
import "slices"
func Entry(){
numbers := []float32{1, 2, 3, 4, 5}
slices.Contains(numbers, 1)
}
`

lprog, err := loadProgramWith2Pkgs(input, input2)
if err != nil {
t.Fatal(err)
}

var anotherPkgInfo *loader.PackageInfo
for k, info := range lprog.AllPackages {
if k.Name() == "p2" {
anotherPkgInfo = info
delete(lprog.AllPackages, k)
}
}
if anotherPkgInfo == nil {
t.Fatal("nil pkg info")
}
mode := InstantiateGenerics
p := buildPackage(lprog, "p", mode)
prog := p.Prog
prog.Build()

npkg := prog.CreatePackage(anotherPkgInfo.Pkg, anotherPkgInfo.Files, &anotherPkgInfo.Info, anotherPkgInfo.Importable)
npkg.Build()

var slicesPkg *Package
for _, pkg := range prog.AllPackages() {
if pkg.Pkg.Name() == "slices" {
slicesPkg = pkg
break
}
}

slicesPkg.Func("Contains").generic.instancesMu.Lock()
instanceNum := len(slicesPkg.Func("Contains").generic.instances)
t.Log(slicesPkg.Func("Contains").generic.instances)
if instanceNum != 2 {
// here, we hope we can get 2 instances
t.Errorf("slices.Contains should have 2 instances but got %d", instanceNum)
}
slicesPkg.Func("Contains").generic.instancesMu.Unlock()
}

// TestNeedsInstance ensures that new method instances can be created via needsInstance,
// that TypeArgs are as expected, and can be accessed via _Instances.
func TestNeedsInstance(t *testing.T) {
Expand Down

0 comments on commit c058a06

Please sign in to comment.