mirror of
https://github.com/golang/go.git
synced 2025-05-17 13:24:38 +00:00
go/types: ObjectString: remove only 1 Alias for "type A = RHS"
As we migrate towards materialized Alias types, the ObjectString for a type A such as type A = B type B = int should be "type A = B", removing exactly one Alias constructor from the type of A. (The previous behavior was "type A = int".) I suspect the existing Alias.{Unalias,Underlying} API is inadequate and that we will need an Alias.RHS accessor that removes exactly one Alias. Other clients such as the import/ export packages will need it, because aliases are not isomorphic to defined types, in which, given type A B type B int the Underlying of A is indeed int. See #66559. Change-Id: I11a4aacbe6dbeeafc3aee31b3c096296b5970cd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/574716 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>
This commit is contained in:
parent
6ffbcd8249
commit
61a3ee5441
@ -542,10 +542,14 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
||||
}
|
||||
if tname.IsAlias() {
|
||||
buf.WriteString(" =")
|
||||
if alias, ok := typ.(*Alias); ok { // materialized? (gotypesalias=1)
|
||||
typ = alias.fromRHS
|
||||
}
|
||||
} else if t, _ := typ.(*TypeParam); t != nil {
|
||||
typ = t.bound
|
||||
} else {
|
||||
// TODO(gri) should this be fromRHS for *Named?
|
||||
// (See discussion in #66559.)
|
||||
typ = under(typ)
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package types2_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -82,66 +83,69 @@ var testObjects = []struct {
|
||||
src string
|
||||
obj string
|
||||
want string
|
||||
alias bool // needs materialized aliases
|
||||
}{
|
||||
{"import \"io\"; var r io.Reader", "r", "var p.r io.Reader"},
|
||||
{"import \"io\"; var r io.Reader", "r", "var p.r io.Reader", false},
|
||||
|
||||
{"const c = 1.2", "c", "const p.c untyped float"},
|
||||
{"const c float64 = 3.14", "c", "const p.c float64"},
|
||||
{"const c = 1.2", "c", "const p.c untyped float", false},
|
||||
{"const c float64 = 3.14", "c", "const p.c float64", false},
|
||||
|
||||
{"type t struct{f int}", "t", "type p.t struct{f int}"},
|
||||
{"type t func(int)", "t", "type p.t func(int)"},
|
||||
{"type t[P any] struct{f P}", "t", "type p.t[P any] struct{f P}"},
|
||||
{"type t[P any] struct{f P}", "t.P", "type parameter P any"},
|
||||
{"type C interface{m()}; type t[P C] struct{}", "t.P", "type parameter P p.C"},
|
||||
{"type t struct{f int}", "t", "type p.t struct{f int}", false},
|
||||
{"type t func(int)", "t", "type p.t func(int)", false},
|
||||
{"type t[P any] struct{f P}", "t", "type p.t[P any] struct{f P}", false},
|
||||
{"type t[P any] struct{f P}", "t.P", "type parameter P any", false},
|
||||
{"type C interface{m()}; type t[P C] struct{}", "t.P", "type parameter P p.C", false},
|
||||
|
||||
{"type t = struct{f int}", "t", "type p.t = struct{f int}"},
|
||||
{"type t = func(int)", "t", "type p.t = func(int)"},
|
||||
{"type t = struct{f int}", "t", "type p.t = struct{f int}", false},
|
||||
{"type t = func(int)", "t", "type p.t = func(int)", false},
|
||||
{"type A = B; type B = int", "A", "type p.A = p.B", true},
|
||||
|
||||
{"var v int", "v", "var p.v int"},
|
||||
{"var v int", "v", "var p.v int", false},
|
||||
|
||||
{"func f(int) string", "f", "func p.f(int) string"},
|
||||
{"func g[P any](x P){}", "g", "func p.g[P any](x P)"},
|
||||
{"func g[P interface{~int}](x P){}", "g.P", "type parameter P interface{~int}"},
|
||||
{"", "any", "type any = interface{}"},
|
||||
{"func f(int) string", "f", "func p.f(int) string", false},
|
||||
{"func g[P any](x P){}", "g", "func p.g[P any](x P)", false},
|
||||
{"func g[P interface{~int}](x P){}", "g.P", "type parameter P interface{~int}", false},
|
||||
{"", "any", "type any = interface{}", false},
|
||||
}
|
||||
|
||||
func TestObjectString(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
for _, test := range testObjects {
|
||||
for i, test := range testObjects {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
if test.alias {
|
||||
t.Setenv("GODEBUG", "gotypesalias=1")
|
||||
}
|
||||
|
||||
src := "package p; " + test.src
|
||||
pkg, err := typecheck(src, nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %s", src, err)
|
||||
continue
|
||||
t.Fatalf("%s: %s", src, err)
|
||||
}
|
||||
|
||||
names := strings.Split(test.obj, ".")
|
||||
if len(names) != 1 && len(names) != 2 {
|
||||
t.Errorf("%s: invalid object path %s", test.src, test.obj)
|
||||
continue
|
||||
t.Fatalf("%s: invalid object path %s", test.src, test.obj)
|
||||
}
|
||||
_, obj := pkg.Scope().LookupParent(names[0], nopos)
|
||||
if obj == nil {
|
||||
t.Errorf("%s: %s not found", test.src, names[0])
|
||||
continue
|
||||
t.Fatalf("%s: %s not found", test.src, names[0])
|
||||
}
|
||||
if len(names) == 2 {
|
||||
if typ, ok := obj.Type().(interface{ TypeParams() *TypeParamList }); ok {
|
||||
obj = lookupTypeParamObj(typ.TypeParams(), names[1])
|
||||
if obj == nil {
|
||||
t.Errorf("%s: %s not found", test.src, test.obj)
|
||||
continue
|
||||
t.Fatalf("%s: %s not found", test.src, test.obj)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("%s: %s has no type parameters", test.src, names[0])
|
||||
continue
|
||||
t.Fatalf("%s: %s has no type parameters", test.src, names[0])
|
||||
}
|
||||
}
|
||||
|
||||
if got := obj.String(); got != test.want {
|
||||
t.Errorf("%s: got %s, want %s", test.src, got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -545,10 +545,14 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
||||
}
|
||||
if tname.IsAlias() {
|
||||
buf.WriteString(" =")
|
||||
if alias, ok := typ.(*Alias); ok { // materialized? (gotypesalias=1)
|
||||
typ = alias.fromRHS
|
||||
}
|
||||
} else if t, _ := typ.(*TypeParam); t != nil {
|
||||
typ = t.bound
|
||||
} else {
|
||||
// TODO(gri) should this be fromRHS for *Named?
|
||||
// (See discussion in #66559.)
|
||||
typ = under(typ)
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -85,66 +86,69 @@ var testObjects = []struct {
|
||||
src string
|
||||
obj string
|
||||
want string
|
||||
alias bool // needs materialized aliases
|
||||
}{
|
||||
{"import \"io\"; var r io.Reader", "r", "var p.r io.Reader"},
|
||||
{"import \"io\"; var r io.Reader", "r", "var p.r io.Reader", false},
|
||||
|
||||
{"const c = 1.2", "c", "const p.c untyped float"},
|
||||
{"const c float64 = 3.14", "c", "const p.c float64"},
|
||||
{"const c = 1.2", "c", "const p.c untyped float", false},
|
||||
{"const c float64 = 3.14", "c", "const p.c float64", false},
|
||||
|
||||
{"type t struct{f int}", "t", "type p.t struct{f int}"},
|
||||
{"type t func(int)", "t", "type p.t func(int)"},
|
||||
{"type t[P any] struct{f P}", "t", "type p.t[P any] struct{f P}"},
|
||||
{"type t[P any] struct{f P}", "t.P", "type parameter P any"},
|
||||
{"type C interface{m()}; type t[P C] struct{}", "t.P", "type parameter P p.C"},
|
||||
{"type t struct{f int}", "t", "type p.t struct{f int}", false},
|
||||
{"type t func(int)", "t", "type p.t func(int)", false},
|
||||
{"type t[P any] struct{f P}", "t", "type p.t[P any] struct{f P}", false},
|
||||
{"type t[P any] struct{f P}", "t.P", "type parameter P any", false},
|
||||
{"type C interface{m()}; type t[P C] struct{}", "t.P", "type parameter P p.C", false},
|
||||
|
||||
{"type t = struct{f int}", "t", "type p.t = struct{f int}"},
|
||||
{"type t = func(int)", "t", "type p.t = func(int)"},
|
||||
{"type t = struct{f int}", "t", "type p.t = struct{f int}", false},
|
||||
{"type t = func(int)", "t", "type p.t = func(int)", false},
|
||||
{"type A = B; type B = int", "A", "type p.A = p.B", true},
|
||||
|
||||
{"var v int", "v", "var p.v int"},
|
||||
{"var v int", "v", "var p.v int", false},
|
||||
|
||||
{"func f(int) string", "f", "func p.f(int) string"},
|
||||
{"func g[P any](x P){}", "g", "func p.g[P any](x P)"},
|
||||
{"func g[P interface{~int}](x P){}", "g.P", "type parameter P interface{~int}"},
|
||||
{"", "any", "type any = interface{}"},
|
||||
{"func f(int) string", "f", "func p.f(int) string", false},
|
||||
{"func g[P any](x P){}", "g", "func p.g[P any](x P)", false},
|
||||
{"func g[P interface{~int}](x P){}", "g.P", "type parameter P interface{~int}", false},
|
||||
{"", "any", "type any = interface{}", false},
|
||||
}
|
||||
|
||||
func TestObjectString(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
for _, test := range testObjects {
|
||||
for i, test := range testObjects {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
if test.alias {
|
||||
t.Setenv("GODEBUG", "gotypesalias=1")
|
||||
}
|
||||
|
||||
src := "package p; " + test.src
|
||||
pkg, err := typecheck(src, nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %s", src, err)
|
||||
continue
|
||||
t.Fatalf("%s: %s", src, err)
|
||||
}
|
||||
|
||||
names := strings.Split(test.obj, ".")
|
||||
if len(names) != 1 && len(names) != 2 {
|
||||
t.Errorf("%s: invalid object path %s", test.src, test.obj)
|
||||
continue
|
||||
t.Fatalf("%s: invalid object path %s", test.src, test.obj)
|
||||
}
|
||||
_, obj := pkg.Scope().LookupParent(names[0], nopos)
|
||||
if obj == nil {
|
||||
t.Errorf("%s: %s not found", test.src, names[0])
|
||||
continue
|
||||
t.Fatalf("%s: %s not found", test.src, names[0])
|
||||
}
|
||||
if len(names) == 2 {
|
||||
if typ, ok := obj.Type().(interface{ TypeParams() *TypeParamList }); ok {
|
||||
obj = lookupTypeParamObj(typ.TypeParams(), names[1])
|
||||
if obj == nil {
|
||||
t.Errorf("%s: %s not found", test.src, test.obj)
|
||||
continue
|
||||
t.Fatalf("%s: %s not found", test.src, test.obj)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("%s: %s has no type parameters", test.src, names[0])
|
||||
continue
|
||||
t.Fatalf("%s: %s has no type parameters", test.src, names[0])
|
||||
}
|
||||
}
|
||||
|
||||
if got := obj.String(); got != test.want {
|
||||
t.Errorf("%s: got %s, want %s", test.src, got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user