mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
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 <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>
This commit is contained in:
parent
2e064cf144
commit
b24ec88bb9
@ -9,6 +9,7 @@ import (
|
|||||||
"cmd/compile/internal/syntax"
|
"cmd/compile/internal/syntax"
|
||||||
"cmd/compile/internal/types2"
|
"cmd/compile/internal/types2"
|
||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
|
"internal/godebug"
|
||||||
"internal/pkgbits"
|
"internal/pkgbits"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -409,7 +410,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types2.Package, string) {
|
|||||||
case pkgbits.ObjAlias:
|
case pkgbits.ObjAlias:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
typ := r.typ()
|
typ := r.typ()
|
||||||
return types2.NewTypeName(pos, objPkg, objName, typ)
|
return newAliasTypeName(pos, objPkg, objName, typ)
|
||||||
|
|
||||||
case pkgbits.ObjConst:
|
case pkgbits.ObjConst:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
@ -533,3 +534,18 @@ func (r *reader) ident(marker pkgbits.SyncMarker) (*types2.Package, string) {
|
|||||||
r.Sync(marker)
|
r.Sync(marker)
|
||||||
return r.pkg(), r.String()
|
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")
|
||||||
|
@ -831,7 +831,11 @@ func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {
|
|||||||
case *types2.TypeName:
|
case *types2.TypeName:
|
||||||
if obj.IsAlias() {
|
if obj.IsAlias() {
|
||||||
w.pos(obj)
|
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
|
return pkgbits.ObjAlias
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,12 @@ func (a *Alias) Obj() *TypeName { return a.obj }
|
|||||||
func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
|
func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
|
||||||
func (a *Alias) String() string { return TypeString(a, nil) }
|
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;
|
// Unalias returns t if it is not an alias type;
|
||||||
// otherwise it follows t's alias chain until it
|
// otherwise it follows t's alias chain until it
|
||||||
// reaches a non-alias type which is then returned.
|
// reaches a non-alias type which is then returned.
|
||||||
|
@ -469,3 +469,10 @@ func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Packa
|
|||||||
pkg := NewPackage(path, "")
|
pkg := NewPackage(path, "")
|
||||||
return pkg, NewChecker(conf, pkg, info).Files(files)
|
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 }
|
||||||
|
@ -7,6 +7,7 @@ package gcimporter
|
|||||||
import (
|
import (
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
"internal/godebug"
|
||||||
"internal/pkgbits"
|
"internal/pkgbits"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
@ -479,7 +480,7 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) {
|
|||||||
case pkgbits.ObjAlias:
|
case pkgbits.ObjAlias:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
typ := r.typ()
|
typ := r.typ()
|
||||||
declare(types.NewTypeName(pos, objPkg, objName, typ))
|
declare(newAliasTypeName(pos, objPkg, objName, typ))
|
||||||
|
|
||||||
case pkgbits.ObjConst:
|
case pkgbits.ObjConst:
|
||||||
pos := r.pos()
|
pos := r.pos()
|
||||||
@ -655,3 +656,15 @@ func pkgScope(pkg *types.Package) *types.Scope {
|
|||||||
}
|
}
|
||||||
return types.Universe
|
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)
|
||||||
|
}
|
||||||
|
@ -35,6 +35,12 @@ func (a *Alias) Obj() *TypeName { return a.obj }
|
|||||||
func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
|
func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
|
||||||
func (a *Alias) String() string { return TypeString(a, nil) }
|
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;
|
// Unalias returns t if it is not an alias type;
|
||||||
// otherwise it follows t's alias chain until it
|
// otherwise it follows t's alias chain until it
|
||||||
// reaches a non-alias type which is then returned.
|
// reaches a non-alias type which is then returned.
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
"internal/godebug"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -173,6 +174,14 @@ func TestEvalPos(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("could not parse file %d: %s", i, err)
|
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)
|
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.
|
// split splits string s at the first occurrence of s, trimming spaces.
|
||||||
func split(s, sep string) (string, string) {
|
func split(s, sep string) (string, string) {
|
||||||
before, after, _ := strings.Cut(s, sep)
|
before, after, _ := strings.Cut(s, sep)
|
||||||
|
@ -117,7 +117,7 @@ type Inst = *Tree[int]
|
|||||||
return n.Underlying().(*Struct).Field(0).Type().(*Pointer).Elem().(*Named)
|
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)
|
Node := firstFieldType(Inst)
|
||||||
Tree := firstFieldType(Node)
|
Tree := firstFieldType(Node)
|
||||||
if !Identical(Inst, Tree) {
|
if !Identical(Inst, Tree) {
|
||||||
|
@ -21,6 +21,7 @@ type S1 struct {
|
|||||||
|
|
||||||
type Eint = E[int]
|
type Eint = E[int]
|
||||||
type Ebool = E[bool]
|
type Ebool = E[bool]
|
||||||
|
type Eint2 = Eint
|
||||||
|
|
||||||
type S2 struct {
|
type S2 struct {
|
||||||
Eint
|
Eint
|
||||||
|
Loading…
x
Reference in New Issue
Block a user