mirror of https://github.com/golang/go.git
go/types, types2: ensure that Alias.actual is 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 golang/go#65455 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>
This commit is contained in:
parent
468f56b10a
commit
10a65649a3
|
|
@ -21,11 +21,14 @@ type Alias struct {
|
||||||
// NewAlias creates a new Alias type with the given type name and rhs.
|
// NewAlias creates a new Alias type with the given type name and rhs.
|
||||||
// rhs must not be nil.
|
// rhs must not be nil.
|
||||||
func NewAlias(obj *TypeName, rhs Type) *Alias {
|
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) 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) }
|
func (a *Alias) String() string { return TypeString(a, nil) }
|
||||||
|
|
||||||
// Type accessors
|
// Type accessors
|
||||||
|
|
@ -36,24 +39,26 @@ func (a *Alias) String() string { return TypeString(a, nil) }
|
||||||
// Consequently, the result is never an alias type.
|
// Consequently, the result is never an alias type.
|
||||||
func Unalias(t Type) Type {
|
func Unalias(t Type) Type {
|
||||||
if a0, _ := t.(*Alias); a0 != nil {
|
if a0, _ := t.(*Alias); a0 != nil {
|
||||||
if a0.actual != nil {
|
return unalias(a0)
|
||||||
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 t
|
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
|
// asNamed returns t as *Named if that is t's
|
||||||
// actual type. It returns nil otherwise.
|
// actual type. It returns nil otherwise.
|
||||||
func asNamed(t Type) *Named {
|
func asNamed(t Type) *Named {
|
||||||
|
|
|
||||||
|
|
@ -2195,6 +2195,12 @@ func TestIssue61737(t *testing.T) {
|
||||||
iface.NumMethods() // unlike go/types, there is no Complete() method, so we complete implicitly
|
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) {
|
func TestIssue15305(t *testing.T) {
|
||||||
const src = "package p; func f() int16; var _ = f(undef)"
|
const src = "package p; func f() int16; var _ = f(undef)"
|
||||||
f := mustParse(src)
|
f := mustParse(src)
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,14 @@ type Alias struct {
|
||||||
// NewAlias creates a new Alias type with the given type name and rhs.
|
// NewAlias creates a new Alias type with the given type name and rhs.
|
||||||
// rhs must not be nil.
|
// rhs must not be nil.
|
||||||
func NewAlias(obj *TypeName, rhs Type) *Alias {
|
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) 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) }
|
func (a *Alias) String() string { return TypeString(a, nil) }
|
||||||
|
|
||||||
// Type accessors
|
// Type accessors
|
||||||
|
|
@ -38,24 +41,26 @@ func (a *Alias) String() string { return TypeString(a, nil) }
|
||||||
// Consequently, the result is never an alias type.
|
// Consequently, the result is never an alias type.
|
||||||
func Unalias(t Type) Type {
|
func Unalias(t Type) Type {
|
||||||
if a0, _ := t.(*Alias); a0 != nil {
|
if a0, _ := t.(*Alias); a0 != nil {
|
||||||
if a0.actual != nil {
|
return unalias(a0)
|
||||||
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 t
|
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
|
// asNamed returns t as *Named if that is t's
|
||||||
// actual type. It returns nil otherwise.
|
// actual type. It returns nil otherwise.
|
||||||
func asNamed(t Type) *Named {
|
func asNamed(t Type) *Named {
|
||||||
|
|
|
||||||
|
|
@ -2196,6 +2196,12 @@ func TestIssue61737(t *testing.T) {
|
||||||
iface.Complete()
|
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) {
|
func TestIssue15305(t *testing.T) {
|
||||||
const src = "package p; func f() int16; var _ = f(undef)"
|
const src = "package p; func f() int16; var _ = f(undef)"
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue