// 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
// 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 {
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)
// 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
// 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 {
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()