]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[release-branch.go1.22] go/types, types2: ensure that Alias.actual is set in NewAlias
authorRob Findley <rfindley@google.com>
Fri, 2 Feb 2024 23:26:06 +0000 (18:26 -0500)
committerCarlos Amedee <carlos@golang.org>
Tue, 27 Feb 2024 21:23:18 +0000 (21:23 +0000)
Types returned by the go/types API must be immutable (or at least
concurrency safe), but NewAlias returned an alias without actual set.

Ensure that actual is set by unaliasing. Also make some superficial
simplifications to unalias, and avoid indirection where unnecessary.

Fixes golang/go#65728

Change-Id: Ic9a020da5accf9032056a924b65c9e9e08cb2e0a
Reviewed-on: https://go-review.googlesource.com/c/go/+/560915
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Robert Griesemer <gri@google.com>
(cherry picked from commit 10a65649a3b2e34ffe8e4202bfa3df851cea0fb4)
Reviewed-on: https://go-review.googlesource.com/c/go/+/564356

src/cmd/compile/internal/types2/alias.go
src/cmd/compile/internal/types2/api_test.go
src/go/types/alias.go
src/go/types/api_test.go

index 2cc57721f9ddab02057354d626db5ffe9c367616..06dfba16976cfaf3f0653ea764a9beec43bcda39 100644 (file)
@@ -21,11 +21,14 @@ type Alias struct {
 // NewAlias creates a new Alias type with the given type name and rhs.
 // rhs must not be nil.
 func NewAlias(obj *TypeName, rhs Type) *Alias {
-       return (*Checker)(nil).newAlias(obj, rhs)
+       alias := (*Checker)(nil).newAlias(obj, rhs)
+       // Ensure that alias.actual is set (#65455).
+       unalias(alias)
+       return alias
 }
 
 func (a *Alias) Obj() *TypeName   { return a.obj }
-func (a *Alias) Underlying() Type { return a.actual.Underlying() }
+func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
 func (a *Alias) String() string   { return TypeString(a, nil) }
 
 // Type accessors
@@ -36,24 +39,26 @@ func (a *Alias) String() string   { return TypeString(a, nil) }
 // Consequently, the result is never an alias type.
 func Unalias(t Type) Type {
        if a0, _ := t.(*Alias); a0 != nil {
-               if a0.actual != nil {
-                       return a0.actual
-               }
-               for a := a0; ; {
-                       t = a.fromRHS
-                       a, _ = t.(*Alias)
-                       if a == nil {
-                               break
-                       }
-               }
-               if t == nil {
-                       panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name))
-               }
-               a0.actual = t
+               return unalias(a0)
        }
        return t
 }
 
+func unalias(a0 *Alias) Type {
+       if a0.actual != nil {
+               return a0.actual
+       }
+       var t Type
+       for a := a0; a != nil; a, _ = t.(*Alias) {
+               t = a.fromRHS
+       }
+       if t == nil {
+               panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name))
+       }
+       a0.actual = t
+       return t
+}
+
 // asNamed returns t as *Named if that is t's
 // actual type. It returns nil otherwise.
 func asNamed(t Type) *Named {
index c70d9144535ebc18d1c550b7cf718e83d11069a5..bacba719553b34c079467ac99341f4954ca7d2f2 100644 (file)
@@ -2195,6 +2195,12 @@ func TestIssue61737(t *testing.T) {
        iface.NumMethods() // unlike go/types, there is no Complete() method, so we complete implicitly
 }
 
+func TestNewAlias_Issue65455(t *testing.T) {
+       obj := NewTypeName(nopos, nil, "A", nil)
+       alias := NewAlias(obj, Typ[Int])
+       alias.Underlying() // must not panic
+}
+
 func TestIssue15305(t *testing.T) {
        const src = "package p; func f() int16; var _ = f(undef)"
        f := mustParse(src)
index 8333a4d9c9cbc2cad76eaf59bdf2c819b6efd0fa..6043c0a9846d64fca39cc9dfc8ce0284a7d7835c 100644 (file)
@@ -23,11 +23,14 @@ type Alias struct {
 // NewAlias creates a new Alias type with the given type name and rhs.
 // rhs must not be nil.
 func NewAlias(obj *TypeName, rhs Type) *Alias {
-       return (*Checker)(nil).newAlias(obj, rhs)
+       alias := (*Checker)(nil).newAlias(obj, rhs)
+       // Ensure that alias.actual is set (#65455).
+       unalias(alias)
+       return alias
 }
 
 func (a *Alias) Obj() *TypeName   { return a.obj }
-func (a *Alias) Underlying() Type { return a.actual.Underlying() }
+func (a *Alias) Underlying() Type { return unalias(a).Underlying() }
 func (a *Alias) String() string   { return TypeString(a, nil) }
 
 // Type accessors
@@ -38,24 +41,26 @@ func (a *Alias) String() string   { return TypeString(a, nil) }
 // Consequently, the result is never an alias type.
 func Unalias(t Type) Type {
        if a0, _ := t.(*Alias); a0 != nil {
-               if a0.actual != nil {
-                       return a0.actual
-               }
-               for a := a0; ; {
-                       t = a.fromRHS
-                       a, _ = t.(*Alias)
-                       if a == nil {
-                               break
-                       }
-               }
-               if t == nil {
-                       panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name))
-               }
-               a0.actual = t
+               return unalias(a0)
        }
        return t
 }
 
+func unalias(a0 *Alias) Type {
+       if a0.actual != nil {
+               return a0.actual
+       }
+       var t Type
+       for a := a0; a != nil; a, _ = t.(*Alias) {
+               t = a.fromRHS
+       }
+       if t == nil {
+               panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name))
+       }
+       a0.actual = t
+       return t
+}
+
 // asNamed returns t as *Named if that is t's
 // actual type. It returns nil otherwise.
 func asNamed(t Type) *Named {
index 0dc5f35dffa107588e8b12e3ac6f29e6cbc4b0c1..52f000980418110716fea6890f16beb2d4e8b48a 100644 (file)
@@ -2196,6 +2196,12 @@ func TestIssue61737(t *testing.T) {
        iface.Complete()
 }
 
+func TestNewAlias_Issue65455(t *testing.T) {
+       obj := NewTypeName(nopos, nil, "A", nil)
+       alias := NewAlias(obj, Typ[Int])
+       alias.Underlying() // must not panic
+}
+
 func TestIssue15305(t *testing.T) {
        const src = "package p; func f() int16; var _ = f(undef)"
        fset := token.NewFileSet()