Skip to content

Commit

Permalink
[release-branch.go1.22] go/types, types2: ensure that Alias.actual is…
Browse files Browse the repository at this point in the history
… set in NewAlias

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 #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 10a6564)
Reviewed-on: https://go-review.googlesource.com/c/go/+/564356
  • Loading branch information
findleyr authored and cagedmantis committed Feb 27, 2024
1 parent 8fe2ad6 commit 3b71998
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 32 deletions.
37 changes: 21 additions & 16 deletions src/cmd/compile/internal/types2/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions src/cmd/compile/internal/types2/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
37 changes: 21 additions & 16 deletions src/go/types/alias.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/go/types/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 3b71998

Please sign in to comment.