-- go.mod --
module example.com
go 1.18

-- generics.go --
package main

// Test of generic function calls.

type I interface {
	Foo()
}

type A struct{}

func (a A) Foo() {}

type B struct{}

func (b B) Foo() {}

func instantiated[X I](x X) {
	x.Foo()
}

var a A
var b B

func main() {
	instantiated[A](a) // static call
	instantiated[B](b) // static call

	local[C]().Foo()

	lambda[A]()()()
}

func local[X I]() I {
	var x X
	return x
}

type C struct{}

func (c C) Foo() {}

func lambda[X I]() func() func() {
	return func() func() {
		var x X
		return x.Foo
	}
}

// WANT:
//
//  edge (*C).Foo --static method call--> (C).Foo
//  edge (A).Foo$bound --static method call--> (A).Foo
//  edge instantiated[example.com.A] --static method call--> (A).Foo
//  edge instantiated[example.com.B] --static method call--> (B).Foo
//  edge main --dynamic method call--> (*C).Foo
//  edge main --dynamic function call--> (A).Foo$bound
//  edge main --dynamic method call--> (C).Foo
//  edge main --static function call--> instantiated[example.com.A]
//  edge main --static function call--> instantiated[example.com.B]
//  edge main --static function call--> lambda[example.com.A]
//  edge main --dynamic function call--> lambda[example.com.A]$1
//  edge main --static function call--> local[example.com.C]
//
//  reachable (*C).Foo
//  reachable (A).Foo
//  reachable (A).Foo$bound
//  reachable (B).Foo
//  reachable (C).Foo
//  reachable instantiated[example.com.A]
//  reachable instantiated[example.com.B]
//  reachable lambda[example.com.A]
//  reachable lambda[example.com.A]$1
//  reachable local[example.com.C]
//
//  rtype *C
//  rtype C
