From: Robert Griesemer Date: Thu, 4 Nov 2021 19:50:25 +0000 (-0700) Subject: cmd/compile/internal/types2: clearer object string for type parameters X-Git-Tag: go1.18beta1~464 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=cfb3dc7710ba35d9932ba9f5242730a97f9ae603;p=gostls13.git cmd/compile/internal/types2: clearer object string for type parameters - print "type parameter" rather than just "type" - print the type bound rather than the underlying type - added an object string test Change-Id: Ibb572ff35b74f2c6ccb27641154f096770541130 Reviewed-on: https://go-review.googlesource.com/c/go/+/361401 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- diff --git a/src/cmd/compile/internal/types2/object.go b/src/cmd/compile/internal/types2/object.go index c7d6709c26..d86c166c72 100644 --- a/src/cmd/compile/internal/types2/object.go +++ b/src/cmd/compile/internal/types2/object.go @@ -458,6 +458,9 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { case *TypeName: tname = obj buf.WriteString("type") + if isTypeParam(typ) { + buf.WriteString(" parameter") + } case *Var: if obj.isField { @@ -503,18 +506,22 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { } if tname != nil { - // We have a type object: Don't print anything more for - // basic types since there's no more information (names - // are the same; see also comment in TypeName.IsAlias). - if _, ok := typ.(*Basic); ok { + switch t := typ.(type) { + case *Basic: + // Don't print anything more for basic types since there's + // no more information. return - } - if named, _ := typ.(*Named); named != nil && named.TypeParams().Len() > 0 { - newTypeWriter(buf, qf).tParamList(named.TypeParams().list()) + case *Named: + if t.TypeParams().Len() > 0 { + newTypeWriter(buf, qf).tParamList(t.TypeParams().list()) + } } if tname.IsAlias() { buf.WriteString(" =") + } else if t, _ := typ.(*TypeParam); t != nil { + typ = t.bound } else { + // TODO(gri) should this be fromRHS for *Named? typ = under(typ) } } diff --git a/src/cmd/compile/internal/types2/object_test.go b/src/cmd/compile/internal/types2/object_test.go index 2fb57d2377..93b3dfb44b 100644 --- a/src/cmd/compile/internal/types2/object_test.go +++ b/src/cmd/compile/internal/types2/object_test.go @@ -6,6 +6,8 @@ package types2_test import ( "cmd/compile/internal/syntax" + "internal/testenv" + "strings" "testing" . "cmd/compile/internal/types2" @@ -86,3 +88,79 @@ func TestEmbeddedMethod(t *testing.T) { t.Fatalf("%s (%p) != %s (%p)", orig, orig, embed, embed) } } + +var testObjects = []struct { + src string + obj string + want string +}{ + {"import \"io\"; var r io.Reader", "r", "var p.r io.Reader"}, + + {"const c = 1.2", "c", "const p.c untyped float"}, + {"const c float64 = 3.14", "c", "const p.c float64"}, + + {"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 interface{}] struct{f P}"}, + {"type t[P any] struct{f P}", "t.P", "type parameter P interface{}"}, + {"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}"}, + {"type t = func(int)", "t", "type p.t = func(int)"}, + + {"var v int", "v", "var p.v int"}, + + {"func f(int) string", "f", "func p.f(int) string"}, + {"func g[P any](x P){}", "g", "func p.g[P interface{}](x P)"}, + {"func g[P interface{~int}](x P){}", "g.P", "type parameter P interface{~int}"}, +} + +func TestObjectString(t *testing.T) { + testenv.MustHaveGoBuild(t) + + for _, test := range testObjects { + src := "package p; " + test.src + pkg, err := makePkg(src) + 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().Lookup(names[0]) + 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 + } + } + + if got := obj.String(); got != test.want { + t.Errorf("%s: got %s, want %s", test.src, got, test.want) + } + } +} + +func lookupTypeParamObj(list *TypeParamList, name string) Object { + for i := 0; i < list.Len(); i++ { + tpar := list.At(i) + if tpar.Obj().Name() == name { + return tpar.Obj() + } + } + return nil +} diff --git a/src/cmd/compile/internal/types2/typestring_test.go b/src/cmd/compile/internal/types2/typestring_test.go index 0ed2934961..eda6835588 100644 --- a/src/cmd/compile/internal/types2/typestring_test.go +++ b/src/cmd/compile/internal/types2/typestring_test.go @@ -129,7 +129,12 @@ func TestTypeString(t *testing.T) { t.Errorf("%s: %s", src, err) continue } - typ := pkg.Scope().Lookup("T").Type().Underlying() + obj := pkg.Scope().Lookup("T") + if obj == nil { + t.Errorf("%s: T not found", test.src) + continue + } + typ := obj.Type().Underlying() if got := typ.String(); got != test.str { t.Errorf("%s: got %s, want %s", test.src, got, test.str) }