Skip to content

Commit b24ec88

Browse files
adonovangopherbot
authored andcommitted
cmd/compile: export/import materialized aliases
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
1 parent 2e064cf commit b24ec88

File tree

9 files changed

+69
-4
lines changed

9 files changed

+69
-4
lines changed

src/cmd/compile/internal/importer/ureader.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"cmd/compile/internal/syntax"
1010
"cmd/compile/internal/types2"
1111
"cmd/internal/src"
12+
"internal/godebug"
1213
"internal/pkgbits"
1314
)
1415

@@ -409,7 +410,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types2.Package, string) {
409410
case pkgbits.ObjAlias:
410411
pos := r.pos()
411412
typ := r.typ()
412-
return types2.NewTypeName(pos, objPkg, objName, typ)
413+
return newAliasTypeName(pos, objPkg, objName, typ)
413414

414415
case pkgbits.ObjConst:
415416
pos := r.pos()
@@ -533,3 +534,18 @@ func (r *reader) ident(marker pkgbits.SyncMarker) (*types2.Package, string) {
533534
r.Sync(marker)
534535
return r.pkg(), r.String()
535536
}
537+
538+
// newAliasTypeName returns a new TypeName, with a materialized *types2.Alias if supported.
539+
func newAliasTypeName(pos syntax.Pos, pkg *types2.Package, name string, rhs types2.Type) *types2.TypeName {
540+
// Copied from x/tools/internal/aliases.NewAlias via
541+
// GOROOT/src/go/internal/gcimporter/ureader.go.
542+
if gotypesalias.Value() == "1" {
543+
tname := types2.NewTypeName(pos, pkg, name, nil)
544+
_ = types2.NewAlias(tname, rhs) // form TypeName -> Alias cycle
545+
return tname
546+
}
547+
return types2.NewTypeName(pos, pkg, name, rhs)
548+
}
549+
550+
// gotypesalias controls the use of Alias types.
551+
var gotypesalias = godebug.New("#gotypesalias")

src/cmd/compile/internal/noder/writer.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,11 @@ func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {
831831
case *types2.TypeName:
832832
if obj.IsAlias() {
833833
w.pos(obj)
834-
w.typ(types2.Unalias(obj.Type()))
834+
t := obj.Type()
835+
if alias, ok := t.(*types2.Alias); ok { // materialized alias
836+
t = alias.Rhs()
837+
}
838+
w.typ(t)
835839
return pkgbits.ObjAlias
836840
}
837841

src/cmd/compile/internal/types2/alias.go

+6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ func (a *Alias) Obj() *TypeName { return a.obj }
3232
func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
3333
func (a *Alias) String() string { return TypeString(a, nil) }
3434

35+
// TODO(adonovan): uncomment when proposal #66559 is accepted.
36+
//
37+
// // Rhs returns the type R on the right-hand side of an alias
38+
// // declaration "type A = R", which may be another alias.
39+
// func (a *Alias) Rhs() Type { return a.fromRHS }
40+
3541
// Unalias returns t if it is not an alias type;
3642
// otherwise it follows t's alias chain until it
3743
// reaches a non-alias type which is then returned.

src/cmd/compile/internal/types2/api.go

+7
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,10 @@ func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Packa
469469
pkg := NewPackage(path, "")
470470
return pkg, NewChecker(conf, pkg, info).Files(files)
471471
}
472+
473+
// Rhs returns the type R on the right-hand side of an alias
474+
// declaration "type A = R", which may be another alias.
475+
//
476+
// TODO(adonovan): move to alias.go (common with go/types) once
477+
// proposal #66559 is accepted.
478+
func (a *Alias) Rhs() Type { return a.fromRHS }

src/go/internal/gcimporter/ureader.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package gcimporter
77
import (
88
"go/token"
99
"go/types"
10+
"internal/godebug"
1011
"internal/pkgbits"
1112
"sort"
1213
)
@@ -479,7 +480,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
479480
case pkgbits.ObjAlias:
480481
pos := r.pos()
481482
typ := r.typ()
482-
declare(types.NewTypeName(pos, objPkg, objName, typ))
483+
declare(newAliasTypeName(pos, objPkg, objName, typ))
483484

484485
case pkgbits.ObjConst:
485486
pos := r.pos()
@@ -655,3 +656,15 @@ func pkgScope(pkg *types.Package) *types.Scope {
655656
}
656657
return types.Universe
657658
}
659+
660+
// newAliasTypeName returns a new TypeName, with a materialized *types.Alias if supported.
661+
func newAliasTypeName(pos token.Pos, pkg *types.Package, name string, rhs types.Type) *types.TypeName {
662+
// When GODEBUG=gotypesalias=1, the Type() of the return value is a
663+
// *types.Alias. Copied from x/tools/internal/aliases.NewAlias.
664+
if godebug.New("gotypesalias").Value() == "1" {
665+
tname := types.NewTypeName(pos, pkg, name, nil)
666+
_ = types.NewAlias(tname, rhs) // form TypeName -> Alias cycle
667+
return tname
668+
}
669+
return types.NewTypeName(pos, pkg, name, rhs)
670+
}

src/go/types/alias.go

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/go/types/eval_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"go/parser"
1414
"go/token"
1515
"go/types"
16+
"internal/godebug"
1617
"internal/testenv"
1718
"strings"
1819
"testing"
@@ -173,6 +174,14 @@ func TestEvalPos(t *testing.T) {
173174
if err != nil {
174175
t.Fatalf("could not parse file %d: %s", i, err)
175176
}
177+
178+
// Materialized aliases give a different (better)
179+
// result for the final test, so skip it for now.
180+
// TODO(adonovan): reenable when gotypesalias=1 is the default.
181+
if gotypesalias.Value() == "1" && strings.Contains(src, "interface{R}.Read") {
182+
continue
183+
}
184+
176185
files = append(files, file)
177186
}
178187

@@ -196,6 +205,9 @@ func TestEvalPos(t *testing.T) {
196205
}
197206
}
198207

208+
// gotypesalias controls the use of Alias types.
209+
var gotypesalias = godebug.New("#gotypesalias")
210+
199211
// split splits string s at the first occurrence of s, trimming spaces.
200212
func split(s, sep string) (string, string) {
201213
before, after, _ := strings.Cut(s, sep)

src/go/types/named_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ type Inst = *Tree[int]
117117
return n.Underlying().(*Struct).Field(0).Type().(*Pointer).Elem().(*Named)
118118
}
119119

120-
Inst := pkg.Scope().Lookup("Inst").Type().(*Pointer).Elem().(*Named)
120+
Inst := Unalias(pkg.Scope().Lookup("Inst").Type()).(*Pointer).Elem().(*Named)
121121
Node := firstFieldType(Inst)
122122
Tree := firstFieldType(Node)
123123
if !Identical(Inst, Tree) {

test/typeparam/struct.go

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type S1 struct {
2121

2222
type Eint = E[int]
2323
type Ebool = E[bool]
24+
type Eint2 = Eint
2425

2526
type S2 struct {
2627
Eint

0 commit comments

Comments
 (0)