From 2e043c7fbc299d5ef2544945a982062739ec65ee Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 24 May 2025 14:38:09 +0200 Subject: [PATCH] compiler: add support for GODEBUG=gotypesalias=1 Since we now require Go 1.22, this became a lot simpler (since we can now refer to `types.Alias` and `types.Unalias`). --- compiler/compiler.go | 22 +++++++++++++++++++++- compiler/interface.go | 7 +++++-- compiler/map.go | 4 +--- flake.nix | 3 --- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index 63d2c86ad..4870df780 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -389,7 +389,7 @@ func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type { // makeLLVMType creates a LLVM type for a Go type. Don't call this, use // getLLVMType instead. func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type { - switch typ := goType.(type) { + switch typ := types.Unalias(goType).(type) { case *types.Array: elemType := c.getLLVMType(typ.Elem()) return llvm.ArrayType(elemType, int(typ.Len())) @@ -497,6 +497,21 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata { llvmType := c.getLLVMType(typ) sizeInBytes := c.targetData.TypeAllocSize(llvmType) switch typ := typ.(type) { + case *types.Alias: + // Implement types.Alias just like types.Named: by treating them like a + // C typedef. + temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{ + Tag: dwarf.TagTypedef, + SizeInBits: sizeInBytes * 8, + AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, + }) + c.ditypes[typ] = temporaryMDNode + md := c.dibuilder.CreateTypedef(llvm.DITypedef{ + Type: c.getDIType(types.Unalias(typ)), // TODO: use typ.Rhs in Go 1.23 + Name: typ.String(), + }) + temporaryMDNode.ReplaceAllUsesWith(md) + return md case *types.Array: return c.dibuilder.CreateArrayType(llvm.DIArrayType{ SizeInBits: sizeInBytes * 8, @@ -859,6 +874,11 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package // Interfaces don't have concrete methods. continue } + if _, isalias := member.Type().(*types.Alias); isalias { + // Aliases don't need to be redefined, since they just refer to + // an already existing type whose methods will be defined. + continue + } // Named type. We should make sure all methods are created. // This includes both functions with pointer receivers and those diff --git a/compiler/interface.go b/compiler/interface.go index dffaeec0a..17c4c399b 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -122,6 +122,9 @@ func (c *compilerContext) pkgPathPtr(pkgpath string) llvm.Value { // This function returns a pointer to the 'kind' field (which might not be the // first field in the struct). func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { + // Resolve alias types: alias types are resolved at compile time. + typ = types.Unalias(typ) + ms := c.program.MethodSets.MethodSet(typ) hasMethodSet := ms.Len() != 0 _, isInterface := typ.Underlying().(*types.Interface) @@ -512,7 +515,7 @@ var basicTypeNames = [...]string{ // interface lowering pass to assign type codes as expected by the reflect // package. See getTypeCodeNum. func getTypeCodeName(t types.Type) (string, bool) { - switch t := t.(type) { + switch t := types.Unalias(t).(type) { case *types.Named: if t.Obj().Parent() != t.Obj().Pkg().Scope() { return "named:" + t.String() + "$local", true @@ -942,7 +945,7 @@ func signature(sig *types.Signature) string { // normalization around `byte` vs `uint8` for example. func typestring(t types.Type) string { // See: https://github.com/golang/go/blob/master/src/go/types/typestring.go - switch t := t.(type) { + switch t := types.Unalias(t).(type) { case *types.Array: return "[" + strconv.FormatInt(t.Len(), 10) + "]" + typestring(t.Elem()) case *types.Basic: diff --git a/compiler/map.go b/compiler/map.go index 71fb3f0da..eb45e6b53 100644 --- a/compiler/map.go +++ b/compiler/map.go @@ -248,7 +248,7 @@ func (b *builder) createMapIteratorNext(rangeVal ssa.Value, llvmRangeVal, it llv // can be compared with runtime.memequal. Note that padding bytes are undef // and can alter two "equal" structs being equal when compared with memequal. func hashmapIsBinaryKey(keyType types.Type) bool { - switch keyType := keyType.(type) { + switch keyType := keyType.Underlying().(type) { case *types.Basic: return keyType.Info()&(types.IsBoolean|types.IsInteger) != 0 case *types.Pointer: @@ -263,8 +263,6 @@ func hashmapIsBinaryKey(keyType types.Type) bool { return true case *types.Array: return hashmapIsBinaryKey(keyType.Elem()) - case *types.Named: - return hashmapIsBinaryKey(keyType.Underlying()) default: return false } diff --git a/flake.nix b/flake.nix index d7d7feb6c..4feea0a4b 100644 --- a/flake.nix +++ b/flake.nix @@ -67,9 +67,6 @@ # has `md5sum`). export MD5SUM=md5sum - # Work around #4819, missing support for generic type aliases. - export GODEBUG=gotypesalias=0 - # Ugly hack to make the Clang resources directory available. export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_20.clang.cc.lib}/lib/clang/20\" -tags=llvm20" '';