]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: ObjectString: remove only 1 Alias for "type A = RHS"
authorAlan Donovan <adonovan@google.com>
Wed, 27 Mar 2024 13:40:24 +0000 (09:40 -0400)
committerGopher Robot <gobot@golang.org>
Wed, 3 Apr 2024 18:49:21 +0000 (18:49 +0000)
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>
src/cmd/compile/internal/types2/object.go
src/cmd/compile/internal/types2/object_test.go
src/go/types/object.go
src/go/types/object_test.go

index e48a4895a77b052c5badfafbbcfd9a46d949b84e..776986f1112ea208b74f7d1c57aa4662dabd27ff 100644 (file)
@@ -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)
                }
        }
index ef1a864ec98bfe97e5cf751925e38d2840b1de0f..20a9a5fd0c8567e16bd6facec6747bc9f1cf4641 100644 (file)
@@ -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
-               }
+       for i, test := range testObjects {
+               t.Run(fmt.Sprint(i), func(t *testing.T) {
+                       if test.alias {
+                               t.Setenv("GODEBUG", "gotypesalias=1")
+                       }
 
-               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
+                       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])
                                }
-                       } 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)
-               }
+                       if got := obj.String(); got != test.want {
+                               t.Errorf("%s: got %s, want %s", test.src, got, test.want)
+                       }
+               })
        }
 }
 
index 7662e94aaf99b3bd3c04eeb2f3f1ae9e8969345d..400b47ebe10c55440552c2aa3093ca69168334d1 100644 (file)
@@ -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)
                }
        }
index c4f361e370342430e676710697a9073336650263..a9f7eed69cc865e202e979ec17cd831fb37d4bb2 100644 (file)
@@ -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
-               }
+       for i, test := range testObjects {
+               t.Run(fmt.Sprint(i), func(t *testing.T) {
+                       if test.alias {
+                               t.Setenv("GODEBUG", "gotypesalias=1")
+                       }
 
-               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
+                       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])
                                }
-                       } 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)
-               }
+                       if got := obj.String(); got != test.want {
+                               t.Errorf("%s: got %s, want %s", test.src, got, test.want)
+                       }
+               })
        }
 }