Preparation for the introduction of alias types.
Because asNamed is not exported, existing external
tests continue to use t.(*Named).
Change-Id: I4754b406dd6b23030d3703a486d6f6620b2464fe
Reviewed-on: https://go-review.googlesource.com/c/go/+/522876
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
--- /dev/null
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types2
+
+// This file will eventually define an Alias type.
+// For now it declares asNamed. Once Alias types
+// exist, asNamed will need to indirect through
+// them as needed.
+
+// asNamed returns t as *Named if that is t's
+// actual type. It returns nil otherwise.
+func asNamed(t Type) *Named {
+ n, _ := t.(*Named)
+ return n
+}
// Cycles are only possible through *Named types.
// The seen map is used to detect cycles and track
// the results of previously seen types.
- if named, _ := t.(*Named); named != nil {
+ if named := asNamed(t); named != nil {
if v, ok := seen[named]; ok {
return v
}
// isImportedConstraint reports whether typ is an imported type constraint.
func (check *Checker) isImportedConstraint(typ Type) bool {
- named, _ := typ.(*Named)
+ named := asNamed(typ)
if named == nil || named.obj.pkg == check.pkg || named.obj.pkg == nil {
return false
}
var rhs Type
check.later(func() {
- if t, _ := obj.typ.(*Named); t != nil { // type may be invalid
+ if t := asNamed(obj.typ); t != nil { // type may be invalid
check.validType(t)
}
// If typ is local, an error was already reported where typ is specified/defined.
// spec: "If the base type is a struct type, the non-blank method
// and field names must be distinct."
- base, _ := obj.typ.(*Named) // shouldn't fail but be conservative
+ base := asNamed(obj.typ) // shouldn't fail but be conservative
if base != nil {
assert(base.TypeArgs().Len() == 0) // collectMethods should not be called on an instantiated type
// Thus, if we have a named pointer type, proceed with the underlying
// pointer type but discard the result if it is a method since we would
// not have found it for T (see also go.dev/issue/8590).
- if t, _ := T.(*Named); t != nil {
+ if t := asNamed(T); t != nil {
if p, _ := t.Underlying().(*Pointer); p != nil {
obj, index, indirect = lookupFieldOrMethodImpl(p, false, pkg, name, false)
if _, ok := obj.(*Func); ok {
// If we have a named type, we may have associated methods.
// Look for those first.
- if named, _ := typ.(*Named); named != nil {
+ if named := asNamed(typ); named != nil {
if alt := seen.lookup(named); alt != nil {
// We have seen this type before, at a more shallow depth
// (note that multiples of this type at the current depth
// If the given type name obj doesn't have a type yet, its type is set to the returned named type.
// The underlying type must not be a *Named.
func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
- if _, ok := underlying.(*Named); ok {
+ if asNamed(underlying) != nil {
panic("underlying type must not be *Named")
}
return (*Checker)(nil).newNamed(obj, underlying, methods)
if underlying == nil {
panic("underlying type must not be nil")
}
- if _, ok := underlying.(*Named); ok {
+ if asNamed(underlying) != nil {
panic("underlying type must not be *Named")
}
t.resolve().underlying = underlying
orig := n.inst.orig
targs := n.inst.targs
- if _, unexpanded := orig.underlying.(*Named); unexpanded {
+ if asNamed(orig.underlying) != nil {
// We should only get a Named underlying type here during type checking
// (for example, in recursive type declarations).
assert(check != nil)
//
// TODO(rfindley): eliminate this function or give it a better name.
func safeUnderlying(typ Type) Type {
- if t, _ := typ.(*Named); t != nil {
+ if t := asNamed(typ); t != nil {
return t.underlying
}
return typ.Underlying()
// TODO(gri) should we include signatures or assert that they are not present?
func isGeneric(t Type) bool {
// A parameterized type is only generic if it doesn't have an instantiation already.
- named, _ := t.(*Named)
+ named := asNamed(t)
return named != nil && named.obj != nil && named.inst == nil && named.TypeParams().Len() > 0
}
// Two named types are identical if their type names originate
// in the same type declaration; if they are instantiated they
// must have identical type argument lists.
- if y, ok := y.(*Named); ok {
+ if y := asNamed(y); y != nil {
// check type arguments before origins to match unifier
// (for correct source code we need to do all checks so
// order doesn't matter)
// Also: Don't report an error via genericType since it will be reported
// again when we type-check the signature.
// TODO(gri) maybe the receiver should be marked as invalid instead?
- if recv, _ := check.genericType(rname, nil).(*Named); recv != nil {
+ if recv := asNamed(check.genericType(rname, nil)); recv != nil {
recvTParams = recv.TypeParams().list()
}
}
}
func IsSyncAtomicAlign64(T Type) bool {
- named, ok := T.(*Named)
- if !ok {
+ named := asNamed(T)
+ if named == nil {
return false
}
obj := named.Obj()
// pos is used for tracing output; start with the type parameter position.
pos := t.obj.pos
// use the (original or possibly instantiated) type bound position if we have one
- if n, _ := bound.(*Named); n != nil {
+ if n := asNamed(bound); n != nil {
pos = n.obj.pos
}
computeInterfaceTypeSet(t.check, pos, ityp)
w.string("any")
break
}
- if t == universeComparable.Type().(*Named).underlying {
+ if t == asNamed(universeComparable.Type()).underlying {
w.string("interface{comparable}")
break
}
return gtyp // error already reported
}
- orig, _ := gtyp.(*Named)
+ orig := asNamed(gtyp)
if orig == nil {
panic(fmt.Sprintf("%v: cannot instantiate %v", x.Pos(), gtyp))
}
}
// create the instance
- inst := check.instance(x.Pos(), orig, targs, nil, check.context()).(*Named)
+ inst := asNamed(check.instance(x.Pos(), orig, targs, nil, check.context()))
def.setUnderlying(inst)
// orig.tparams may not be set up, so we need to do expansion later.
// under must only be called when a type is known
// to be fully set up.
func under(t Type) Type {
- if t, _ := t.(*Named); t != nil {
+ if t := asNamed(t); t != nil {
return t.under()
}
return t.Underlying()
// Ensure that if we have at least one
// - defined type, make sure one is in y
// - type parameter recorded with u, make sure one is in x
- if _, ok := x.(*Named); ok || u.asTypeParam(y) != nil {
+ if asNamed(x) != nil || u.asTypeParam(y) != nil {
if traceInference {
u.tracef("%s ≡ %s\t// swap", y, x)
}
// we will fail at function instantiation or argument assignment time.
//
// If we have at least one defined type, there is one in y.
- if ny, _ := y.(*Named); mode&exact == 0 && ny != nil && isTypeLit(x) && !(u.enableInterfaceInference && IsInterface(x)) {
+ if ny := asNamed(y); mode&exact == 0 && ny != nil && isTypeLit(x) && !(u.enableInterfaceInference && IsInterface(x)) {
if traceInference {
u.tracef("%s ≡ under %s", x, ny)
}
// We have a match, possibly through underlying types.
xi := asInterface(x)
yi := asInterface(y)
- _, xn := x.(*Named)
- _, yn := y.(*Named)
+ xn := asNamed(x) != nil
+ yn := asNamed(y) != nil
// If we have two interfaces, what to do depends on
// whether they are named and their method sets.
if xi != nil && yi != nil {
case *Named:
// Two named types unify if their type names originate in the same type declaration.
// If they are instantiated, their type argument lists must unify.
- if y, ok := y.(*Named); ok {
+ if y := asNamed(y); y != nil {
// Check type arguments before origins so they unify
// even if the origins don't match; for better error
// messages (see go.dev/issue/53692).
return // nothing to do
}
// fix Obj link for named types
- if typ, _ := obj.Type().(*Named); typ != nil {
+ if typ := asNamed(obj.Type()); typ != nil {
typ.obj = obj.(*TypeName)
}
// exported identifiers go into package unsafe
--- /dev/null
+// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+// This file will eventually define an Alias type.
+// For now it declares asNamed. Once Alias types
+// exist, asNamed will need to indirect through
+// them as needed.
+
+// asNamed returns t as *Named if that is t's
+// actual type. It returns nil otherwise.
+func asNamed(t Type) *Named {
+ n, _ := t.(*Named)
+ return n
+}
// Cycles are only possible through *Named types.
// The seen map is used to detect cycles and track
// the results of previously seen types.
- if named, _ := t.(*Named); named != nil {
+ if named := asNamed(t); named != nil {
if v, ok := seen[named]; ok {
return v
}
// isImportedConstraint reports whether typ is an imported type constraint.
func (check *Checker) isImportedConstraint(typ Type) bool {
- named, _ := typ.(*Named)
+ named := asNamed(typ)
if named == nil || named.obj.pkg == check.pkg || named.obj.pkg == nil {
return false
}
var rhs Type
check.later(func() {
- if t, _ := obj.typ.(*Named); t != nil { // type may be invalid
+ if t := asNamed(obj.typ); t != nil { // type may be invalid
check.validType(t)
}
// If typ is local, an error was already reported where typ is specified/defined.
// spec: "If the base type is a struct type, the non-blank method
// and field names must be distinct."
- base, _ := obj.typ.(*Named) // shouldn't fail but be conservative
+ base := asNamed(obj.typ) // shouldn't fail but be conservative
if base != nil {
assert(base.TypeArgs().Len() == 0) // collectMethods should not be called on an instantiated type
type action func(in *ast.File)
var filemap = map[string]action{
+ "alias.go": nil,
"array.go": nil,
"basic.go": nil,
"chan.go": nil,
// The result is nil if the i'th embedded type is not a defined type.
//
// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types.
-func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named); return tname }
+func (t *Interface) Embedded(i int) *Named { return asNamed(t.embeddeds[i]) }
// EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] }
// Thus, if we have a named pointer type, proceed with the underlying
// pointer type but discard the result if it is a method since we would
// not have found it for T (see also go.dev/issue/8590).
- if t, _ := T.(*Named); t != nil {
+ if t := asNamed(T); t != nil {
if p, _ := t.Underlying().(*Pointer); p != nil {
obj, index, indirect = lookupFieldOrMethodImpl(p, false, pkg, name, false)
if _, ok := obj.(*Func); ok {
// If we have a named type, we may have associated methods.
// Look for those first.
- if named, _ := typ.(*Named); named != nil {
+ if named := asNamed(typ); named != nil {
if alt := seen.lookup(named); alt != nil {
// We have seen this type before, at a more shallow depth
// (note that multiples of this type at the current depth
// (spec: "The type denoted by T is called the receiver base type;
// it must not be a pointer or interface type and it must be declared
// in the same package as the method.").
- if t, _ := T.(*Named); t != nil && isPointer(t) {
+ if t := asNamed(T); t != nil && isPointer(t) {
return &emptyMethodSet
}
// If we have a named type, we may have associated methods.
// Look for those first.
- if named, _ := typ.(*Named); named != nil {
+ if named := asNamed(typ); named != nil {
if alt := seen.lookup(named); alt != nil {
// We have seen this type before, at a more shallow depth
// (note that multiples of this type at the current depth
// If the given type name obj doesn't have a type yet, its type is set to the returned named type.
// The underlying type must not be a *Named.
func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
- if _, ok := underlying.(*Named); ok {
+ if asNamed(underlying) != nil {
panic("underlying type must not be *Named")
}
return (*Checker)(nil).newNamed(obj, underlying, methods)
if underlying == nil {
panic("underlying type must not be nil")
}
- if _, ok := underlying.(*Named); ok {
+ if asNamed(underlying) != nil {
panic("underlying type must not be *Named")
}
t.resolve().underlying = underlying
orig := n.inst.orig
targs := n.inst.targs
- if _, unexpanded := orig.underlying.(*Named); unexpanded {
+ if asNamed(orig.underlying) != nil {
// We should only get a Named underlying type here during type checking
// (for example, in recursive type declarations).
assert(check != nil)
//
// TODO(rfindley): eliminate this function or give it a better name.
func safeUnderlying(typ Type) Type {
- if t, _ := typ.(*Named); t != nil {
+ if t := asNamed(typ); t != nil {
return t.underlying
}
return typ.Underlying()
// TODO(gri) should we include signatures or assert that they are not present?
func isGeneric(t Type) bool {
// A parameterized type is only generic if it doesn't have an instantiation already.
- named, _ := t.(*Named)
+ named := asNamed(t)
return named != nil && named.obj != nil && named.inst == nil && named.TypeParams().Len() > 0
}
// Two named types are identical if their type names originate
// in the same type declaration; if they are instantiated they
// must have identical type argument lists.
- if y, ok := y.(*Named); ok {
+ if y := asNamed(y); y != nil {
// check type arguments before origins to match unifier
// (for correct source code we need to do all checks so
// order doesn't matter)
// Also: Don't report an error via genericType since it will be reported
// again when we type-check the signature.
// TODO(gri) maybe the receiver should be marked as invalid instead?
- if recv, _ := check.genericType(rname, nil).(*Named); recv != nil {
+ if recv := asNamed(check.genericType(rname, nil)); recv != nil {
recvTParams = recv.TypeParams().list()
}
}
}
func _IsSyncAtomicAlign64(T Type) bool {
- named, ok := T.(*Named)
- if !ok {
+ named := asNamed(T)
+ if named == nil {
return false
}
obj := named.Obj()
// pos is used for tracing output; start with the type parameter position.
pos := t.obj.pos
// use the (original or possibly instantiated) type bound position if we have one
- if n, _ := bound.(*Named); n != nil {
+ if n := asNamed(bound); n != nil {
pos = n.obj.pos
}
computeInterfaceTypeSet(t.check, pos, ityp)
w.string("any")
break
}
- if t == universeComparable.Type().(*Named).underlying {
+ if t == asNamed(universeComparable.Type()).underlying {
w.string("interface{comparable}")
break
}
return gtyp // error already reported
}
- orig, _ := gtyp.(*Named)
+ orig := asNamed(gtyp)
if orig == nil {
panic(fmt.Sprintf("%v: cannot instantiate %v", ix.Pos(), gtyp))
}
}
// create the instance
- inst := check.instance(ix.Pos(), orig, targs, nil, check.context()).(*Named)
+ inst := asNamed(check.instance(ix.Pos(), orig, targs, nil, check.context()))
def.setUnderlying(inst)
// orig.tparams may not be set up, so we need to do expansion later.
// under must only be called when a type is known
// to be fully set up.
func under(t Type) Type {
- if t, _ := t.(*Named); t != nil {
+ if t := asNamed(t); t != nil {
return t.under()
}
return t.Underlying()
// Ensure that if we have at least one
// - defined type, make sure one is in y
// - type parameter recorded with u, make sure one is in x
- if _, ok := x.(*Named); ok || u.asTypeParam(y) != nil {
+ if asNamed(x) != nil || u.asTypeParam(y) != nil {
if traceInference {
u.tracef("%s ≡ %s\t// swap", y, x)
}
// we will fail at function instantiation or argument assignment time.
//
// If we have at least one defined type, there is one in y.
- if ny, _ := y.(*Named); mode&exact == 0 && ny != nil && isTypeLit(x) && !(u.enableInterfaceInference && IsInterface(x)) {
+ if ny := asNamed(y); mode&exact == 0 && ny != nil && isTypeLit(x) && !(u.enableInterfaceInference && IsInterface(x)) {
if traceInference {
u.tracef("%s ≡ under %s", x, ny)
}
// We have a match, possibly through underlying types.
xi := asInterface(x)
yi := asInterface(y)
- _, xn := x.(*Named)
- _, yn := y.(*Named)
+ xn := asNamed(x) != nil
+ yn := asNamed(y) != nil
// If we have two interfaces, what to do depends on
// whether they are named and their method sets.
if xi != nil && yi != nil {
case *Named:
// Two named types unify if their type names originate in the same type declaration.
// If they are instantiated, their type argument lists must unify.
- if y, ok := y.(*Named); ok {
+ if y := asNamed(y); y != nil {
// Check type arguments before origins so they unify
// even if the origins don't match; for better error
// messages (see go.dev/issue/53692).
return // nothing to do
}
// fix Obj link for named types
- if typ, _ := obj.Type().(*Named); typ != nil {
+ if typ := asNamed(obj.Type()); typ != nil {
typ.obj = obj.(*TypeName)
}
// exported identifiers go into package unsafe