]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: export/import materialized aliases
authorAlan Donovan <adonovan@google.com>
Wed, 27 Mar 2024 13:44:01 +0000 (09:44 -0400)
committerGopher Robot <gobot@golang.org>
Fri, 5 Apr 2024 16:29:58 +0000 (16:29 +0000)
This CL changes the compiler's type import/export logic
to create and preserve materialized Alias types
when GODEBUG=gotypesaliases=1.

In conjunction with CL 574717, it allows the x/tools
tests to pass with GODEBUG=gotypesaliases=1.

Updates #65294
Updates #64581
Fixes #66550

Change-Id: I70b9279f4e0ae7a1f95ad153c4e6909a878915a4
Reviewed-on: https://go-review.googlesource.com/c/go/+/574737
Auto-Submit: Alan Donovan <adonovan@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/importer/ureader.go
src/cmd/compile/internal/noder/writer.go
src/cmd/compile/internal/types2/alias.go
src/cmd/compile/internal/types2/api.go
src/go/internal/gcimporter/ureader.go
src/go/types/alias.go
src/go/types/eval_test.go
src/go/types/named_test.go
test/typeparam/struct.go

index f5c2f41069de8b40086ceadba60eae624814f494..3488f1314882e369594e12c116210c19dfe60fce 100644 (file)
@@ -9,6 +9,7 @@ import (
        "cmd/compile/internal/syntax"
        "cmd/compile/internal/types2"
        "cmd/internal/src"
+       "internal/godebug"
        "internal/pkgbits"
 )
 
@@ -409,7 +410,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types2.Package, string) {
                case pkgbits.ObjAlias:
                        pos := r.pos()
                        typ := r.typ()
-                       return types2.NewTypeName(pos, objPkg, objName, typ)
+                       return newAliasTypeName(pos, objPkg, objName, typ)
 
                case pkgbits.ObjConst:
                        pos := r.pos()
@@ -533,3 +534,18 @@ func (r *reader) ident(marker pkgbits.SyncMarker) (*types2.Package, string) {
        r.Sync(marker)
        return r.pkg(), r.String()
 }
+
+// newAliasTypeName returns a new TypeName, with a materialized *types2.Alias if supported.
+func newAliasTypeName(pos syntax.Pos, pkg *types2.Package, name string, rhs types2.Type) *types2.TypeName {
+       // Copied from x/tools/internal/aliases.NewAlias via
+       // GOROOT/src/go/internal/gcimporter/ureader.go.
+       if gotypesalias.Value() == "1" {
+               tname := types2.NewTypeName(pos, pkg, name, nil)
+               _ = types2.NewAlias(tname, rhs) // form TypeName -> Alias cycle
+               return tname
+       }
+       return types2.NewTypeName(pos, pkg, name, rhs)
+}
+
+// gotypesalias controls the use of Alias types.
+var gotypesalias = godebug.New("#gotypesalias")
index 71606a915f65ba2f81447c49a48972caed25e168..785176b3b57b8454f9a4c2bfa76ae5bd870a125d 100644 (file)
@@ -831,7 +831,11 @@ func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {
        case *types2.TypeName:
                if obj.IsAlias() {
                        w.pos(obj)
-                       w.typ(types2.Unalias(obj.Type()))
+                       t := obj.Type()
+                       if alias, ok := t.(*types2.Alias); ok { // materialized alias
+                               t = alias.Rhs()
+                       }
+                       w.typ(t)
                        return pkgbits.ObjAlias
                }
 
index 149cd3b265d7299780a0a0711609be2ed2cd2837..7bc0e5a9f949e1b2aab6043418ff7fc2d696c3f2 100644 (file)
@@ -32,6 +32,12 @@ func (a *Alias) Obj() *TypeName   { return a.obj }
 func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
 func (a *Alias) String() string   { return TypeString(a, nil) }
 
+// TODO(adonovan): uncomment when proposal #66559 is accepted.
+//
+// // Rhs returns the type R on the right-hand side of an alias
+// // declaration "type A = R", which may be another alias.
+// func (a *Alias) Rhs() Type { return a.fromRHS }
+
 // Unalias returns t if it is not an alias type;
 // otherwise it follows t's alias chain until it
 // reaches a non-alias type which is then returned.
index bb02d9198e6ff3e38dc7ec7617a2e41b4e8bc316..0b44d4ff38bb35dcfb1401f0d5c0145b8a6449f6 100644 (file)
@@ -469,3 +469,10 @@ func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Packa
        pkg := NewPackage(path, "")
        return pkg, NewChecker(conf, pkg, info).Files(files)
 }
+
+// Rhs returns the type R on the right-hand side of an alias
+// declaration "type A = R", which may be another alias.
+//
+// TODO(adonovan): move to alias.go (common with go/types) once
+// proposal #66559 is accepted.
+func (a *Alias) Rhs() Type { return a.fromRHS }
index 5397a2796f786900bd315ab98621b1b5a170bf03..b7d7b6c86178f784fbf759151b578d189440dc8a 100644 (file)
@@ -7,6 +7,7 @@ package gcimporter
 import (
        "go/token"
        "go/types"
+       "internal/godebug"
        "internal/pkgbits"
        "sort"
 )
@@ -479,7 +480,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
                case pkgbits.ObjAlias:
                        pos := r.pos()
                        typ := r.typ()
-                       declare(types.NewTypeName(pos, objPkg, objName, typ))
+                       declare(newAliasTypeName(pos, objPkg, objName, typ))
 
                case pkgbits.ObjConst:
                        pos := r.pos()
@@ -655,3 +656,15 @@ func pkgScope(pkg *types.Package) *types.Scope {
        }
        return types.Universe
 }
+
+// newAliasTypeName returns a new TypeName, with a materialized *types.Alias if supported.
+func newAliasTypeName(pos token.Pos, pkg *types.Package, name string, rhs types.Type) *types.TypeName {
+       // When GODEBUG=gotypesalias=1, the Type() of the return value is a
+       // *types.Alias. Copied from x/tools/internal/aliases.NewAlias.
+       if godebug.New("gotypesalias").Value() == "1" {
+               tname := types.NewTypeName(pos, pkg, name, nil)
+               _ = types.NewAlias(tname, rhs) // form TypeName -> Alias cycle
+               return tname
+       }
+       return types.NewTypeName(pos, pkg, name, rhs)
+}
index e32ddbcb331332687a409c8be59b4c19a4df8c21..3490d26c203bad62baf84dcfc27f843d1600cb5b 100644 (file)
@@ -35,6 +35,12 @@ func (a *Alias) Obj() *TypeName   { return a.obj }
 func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
 func (a *Alias) String() string   { return TypeString(a, nil) }
 
+// TODO(adonovan): uncomment when proposal #66559 is accepted.
+//
+// // Rhs returns the type R on the right-hand side of an alias
+// // declaration "type A = R", which may be another alias.
+// func (a *Alias) Rhs() Type { return a.fromRHS }
+
 // Unalias returns t if it is not an alias type;
 // otherwise it follows t's alias chain until it
 // reaches a non-alias type which is then returned.
index 1521f2fe41915a1c393709fd04177f08ffe5c924..c0ac8225acb77cbe20f8c82ae0d078e54900d381 100644 (file)
@@ -13,6 +13,7 @@ import (
        "go/parser"
        "go/token"
        "go/types"
+       "internal/godebug"
        "internal/testenv"
        "strings"
        "testing"
@@ -173,6 +174,14 @@ func TestEvalPos(t *testing.T) {
                if err != nil {
                        t.Fatalf("could not parse file %d: %s", i, err)
                }
+
+               // Materialized aliases give a different (better)
+               // result for the final test, so skip it for now.
+               // TODO(adonovan): reenable when gotypesalias=1 is the default.
+               if gotypesalias.Value() == "1" && strings.Contains(src, "interface{R}.Read") {
+                       continue
+               }
+
                files = append(files, file)
        }
 
@@ -196,6 +205,9 @@ func TestEvalPos(t *testing.T) {
        }
 }
 
+// gotypesalias controls the use of Alias types.
+var gotypesalias = godebug.New("#gotypesalias")
+
 // split splits string s at the first occurrence of s, trimming spaces.
 func split(s, sep string) (string, string) {
        before, after, _ := strings.Cut(s, sep)
index d930874f1201d48e7a031ed45f8464f52fc8f8e8..effeeb6f5c4299df2e933ff1d1e3b94f77830986 100644 (file)
@@ -117,7 +117,7 @@ type Inst = *Tree[int]
                return n.Underlying().(*Struct).Field(0).Type().(*Pointer).Elem().(*Named)
        }
 
-       Inst := pkg.Scope().Lookup("Inst").Type().(*Pointer).Elem().(*Named)
+       Inst := Unalias(pkg.Scope().Lookup("Inst").Type()).(*Pointer).Elem().(*Named)
        Node := firstFieldType(Inst)
        Tree := firstFieldType(Node)
        if !Identical(Inst, Tree) {
index 2dad9087bc9aeece5eb7a527e6aa805a727acf66..fee38eccc34eddd77168520dfd33ad33b2e7c5bf 100644 (file)
@@ -21,6 +21,7 @@ type S1 struct {
 
 type Eint = E[int]
 type Ebool = E[bool]
+type Eint2 = Eint
 
 type S2 struct {
        Eint