diff --git a/compiler/compiler.go b/compiler/compiler.go index f6ae3cb0..1ca43468 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -18,6 +18,7 @@ import ( "github.com/tinygo-org/tinygo/compiler/llvmutil" "github.com/tinygo-org/tinygo/loader" "golang.org/x/tools/go/ssa" + "golang.org/x/tools/go/types/typeutil" "tinygo.org/x/go-llvm" ) @@ -70,7 +71,7 @@ type compilerContext struct { cu llvm.Metadata difiles map[string]llvm.Metadata ditypes map[types.Type]llvm.Metadata - llvmTypes map[types.Type]llvm.Type + llvmTypes typeutil.Map machine llvm.TargetMachine targetData llvm.TargetData intType llvm.Type @@ -95,7 +96,6 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C DumpSSA: dumpSSA, difiles: make(map[string]llvm.Metadata), ditypes: make(map[types.Type]llvm.Metadata), - llvmTypes: make(map[types.Type]llvm.Type), machine: machine, targetData: machine.CreateTargetData(), astComments: map[string]*ast.CommentGroup{}, @@ -329,12 +329,16 @@ func (c *compilerContext) getLLVMRuntimeType(name string) llvm.Type { // important for named struct types (which should only be created once). func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type { // Try to load the LLVM type from the cache. - if t, ok := c.llvmTypes[goType]; ok { - return t + // Note: *types.Named isn't unique when working with generics. + // See https://github.com/golang/go/issues/53914 + // This is the reason for using typeutil.Map to lookup LLVM types for Go types. + ival := c.llvmTypes.At(goType) + if ival != nil { + return ival.(llvm.Type) } // Not already created, so adding this type to the cache. llvmType := c.makeLLVMType(goType) - c.llvmTypes[goType] = llvmType + c.llvmTypes.Set(goType, llvmType) return llvmType } @@ -391,7 +395,7 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type { // self-referencing types such as linked lists. llvmName := typ.Obj().Pkg().Path() + "." + typ.Obj().Name() llvmType := c.ctx.StructCreateNamed(llvmName) - c.llvmTypes[goType] = llvmType // avoid infinite recursion + c.llvmTypes.Set(goType, llvmType) // avoid infinite recursion underlying := c.getLLVMType(st) llvmType.StructSetBody(underlying.StructElementTypes(), false) return llvmType diff --git a/testdata/generics.go b/testdata/generics.go index 9f1a1970..2286bb0d 100644 --- a/testdata/generics.go +++ b/testdata/generics.go @@ -3,6 +3,9 @@ package main func main() { println("add:", Add(3, 5)) println("add:", Add(int8(3), 5)) + + var c C[int] + c.F() // issue 2951 } type Integer interface { @@ -12,3 +15,8 @@ type Integer interface { func Add[T Integer](a, b T) T { return a + b } + +// Test for https://github.com/tinygo-org/tinygo/issues/2951 +type C[V any] struct{} + +func (c *C[V]) F() {}