diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go index e48a4895a7..776986f111 100644 --- a/src/cmd/compile/internal/types2/object.go +++ b/src/cmd/compile/internal/types2/object.go @@ -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) } } diff --git a/src/cmd/compile/internal/types2/object_test.go b/src/cmd/compile/internal/types2/object_test.go index ef1a864ec9..20a9a5fd0c 100644 --- a/src/cmd/compile/internal/types2/object_test.go +++ b/src/cmd/compile/internal/types2/object_test.go @@ -5,6 +5,7 @@ package types2_test import ( + "fmt" "internal/testenv" "strings" "testing" @@ -79,69 +80,72 @@ func TestEmbeddedMethod(t *testing.T) { } var testObjects = []struct { - src string - obj string - want string + 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 { - src := "package p; " + test.src - pkg, err := typecheck(src, nil, nil) - if err != nil { - t.Errorf("%s: %s", src, err) - continue - } - - names := strings.Split(test.obj, ".") - if len(names) != 1 && len(names) != 2 { - t.Errorf("%s: invalid object path %s", test.src, test.obj) - continue - } - _, obj := pkg.Scope().LookupParent(names[0], nopos) - if obj == nil { - t.Errorf("%s: %s not found", test.src, names[0]) - continue - } - 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 - } - } else { - t.Errorf("%s: %s has no type parameters", test.src, names[0]) - continue + for i, test := range testObjects { + t.Run(fmt.Sprint(i), func(t *testing.T) { + if test.alias { + t.Setenv("GODEBUG", "gotypesalias=1") } - } - if got := obj.String(); got != test.want { - t.Errorf("%s: got %s, want %s", test.src, got, test.want) - } + src := "package p; " + test.src + pkg, err := typecheck(src, nil, nil) + if err != nil { + t.Fatalf("%s: %s", src, err) + } + + names := strings.Split(test.obj, ".") + if len(names) != 1 && len(names) != 2 { + t.Fatalf("%s: invalid object path %s", test.src, test.obj) + } + _, obj := pkg.Scope().LookupParent(names[0], nopos) + if obj == nil { + 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.Fatalf("%s: %s not found", test.src, test.obj) + } + } else { + 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) + } + }) } } diff --git a/src/go/types/object.go b/src/go/types/object.go index 7662e94aaf..400b47ebe1 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -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) } } diff --git a/src/go/types/object_test.go b/src/go/types/object_test.go index c4f361e370..a9f7eed69c 100644 --- a/src/go/types/object_test.go +++ b/src/go/types/object_test.go @@ -8,6 +8,7 @@ package types_test import ( + "fmt" "internal/testenv" "strings" "testing" @@ -82,69 +83,72 @@ func TestEmbeddedMethod(t *testing.T) { } var testObjects = []struct { - src string - obj string - want string + 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 { - src := "package p; " + test.src - pkg, err := typecheck(src, nil, nil) - if err != nil { - t.Errorf("%s: %s", src, err) - continue - } - - names := strings.Split(test.obj, ".") - if len(names) != 1 && len(names) != 2 { - t.Errorf("%s: invalid object path %s", test.src, test.obj) - continue - } - _, obj := pkg.Scope().LookupParent(names[0], nopos) - if obj == nil { - t.Errorf("%s: %s not found", test.src, names[0]) - continue - } - 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 - } - } else { - t.Errorf("%s: %s has no type parameters", test.src, names[0]) - continue + for i, test := range testObjects { + t.Run(fmt.Sprint(i), func(t *testing.T) { + if test.alias { + t.Setenv("GODEBUG", "gotypesalias=1") } - } - if got := obj.String(); got != test.want { - t.Errorf("%s: got %s, want %s", test.src, got, test.want) - } + src := "package p; " + test.src + pkg, err := typecheck(src, nil, nil) + if err != nil { + t.Fatalf("%s: %s", src, err) + } + + names := strings.Split(test.obj, ".") + if len(names) != 1 && len(names) != 2 { + t.Fatalf("%s: invalid object path %s", test.src, test.obj) + } + _, obj := pkg.Scope().LookupParent(names[0], nopos) + if obj == nil { + 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.Fatalf("%s: %s not found", test.src, test.obj) + } + } else { + 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) + } + }) } }