compiler: fix issue with methods on generic structs

Этот коммит содержится в:
Phil Kedy 2022-07-18 21:19:57 -04:00 коммит произвёл Ayke
родитель 5026047cde
коммит 58072a5167
2 изменённых файлов: 18 добавлений и 6 удалений

Просмотреть файл

@ -18,6 +18,7 @@ import (
"github.com/tinygo-org/tinygo/compiler/llvmutil" "github.com/tinygo-org/tinygo/compiler/llvmutil"
"github.com/tinygo-org/tinygo/loader" "github.com/tinygo-org/tinygo/loader"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/types/typeutil"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@ -70,7 +71,7 @@ type compilerContext struct {
cu llvm.Metadata cu llvm.Metadata
difiles map[string]llvm.Metadata difiles map[string]llvm.Metadata
ditypes map[types.Type]llvm.Metadata ditypes map[types.Type]llvm.Metadata
llvmTypes map[types.Type]llvm.Type llvmTypes typeutil.Map
machine llvm.TargetMachine machine llvm.TargetMachine
targetData llvm.TargetData targetData llvm.TargetData
intType llvm.Type intType llvm.Type
@ -95,7 +96,6 @@ func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *C
DumpSSA: dumpSSA, DumpSSA: dumpSSA,
difiles: make(map[string]llvm.Metadata), difiles: make(map[string]llvm.Metadata),
ditypes: make(map[types.Type]llvm.Metadata), ditypes: make(map[types.Type]llvm.Metadata),
llvmTypes: make(map[types.Type]llvm.Type),
machine: machine, machine: machine,
targetData: machine.CreateTargetData(), targetData: machine.CreateTargetData(),
astComments: map[string]*ast.CommentGroup{}, 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). // important for named struct types (which should only be created once).
func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type { func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type {
// Try to load the LLVM type from the cache. // Try to load the LLVM type from the cache.
if t, ok := c.llvmTypes[goType]; ok { // Note: *types.Named isn't unique when working with generics.
return t // 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. // Not already created, so adding this type to the cache.
llvmType := c.makeLLVMType(goType) llvmType := c.makeLLVMType(goType)
c.llvmTypes[goType] = llvmType c.llvmTypes.Set(goType, llvmType)
return llvmType return llvmType
} }
@ -391,7 +395,7 @@ func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type {
// self-referencing types such as linked lists. // self-referencing types such as linked lists.
llvmName := typ.Obj().Pkg().Path() + "." + typ.Obj().Name() llvmName := typ.Obj().Pkg().Path() + "." + typ.Obj().Name()
llvmType := c.ctx.StructCreateNamed(llvmName) llvmType := c.ctx.StructCreateNamed(llvmName)
c.llvmTypes[goType] = llvmType // avoid infinite recursion c.llvmTypes.Set(goType, llvmType) // avoid infinite recursion
underlying := c.getLLVMType(st) underlying := c.getLLVMType(st)
llvmType.StructSetBody(underlying.StructElementTypes(), false) llvmType.StructSetBody(underlying.StructElementTypes(), false)
return llvmType return llvmType

8
testdata/generics.go предоставленный
Просмотреть файл

@ -3,6 +3,9 @@ package main
func main() { func main() {
println("add:", Add(3, 5)) println("add:", Add(3, 5))
println("add:", Add(int8(3), 5)) println("add:", Add(int8(3), 5))
var c C[int]
c.F() // issue 2951
} }
type Integer interface { type Integer interface {
@ -12,3 +15,8 @@ type Integer interface {
func Add[T Integer](a, b T) T { func Add[T Integer](a, b T) T {
return a + b return a + b
} }
// Test for https://github.com/tinygo-org/tinygo/issues/2951
type C[V any] struct{}
func (c *C[V]) F() {}